<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<meta name=Generator content="Microsoft Word 14 (filtered)">

<style>
<!--
 /* Font Definitions */
 @font-face
	{font-family:Wingdings;
	panose-1:5 0 0 0 0 0 0 0 0 0;}
@font-face
	{font-family:宋体;
	panose-1:2 1 6 0 3 1 1 1 1 1;}
@font-face
	{font-family:黑体;
	panose-1:2 1 6 9 6 1 1 1 1 1;}
@font-face
	{font-family:黑体;
	panose-1:2 1 6 9 6 1 1 1 1 1;}
@font-face
	{font-family:方正小标宋简体;}
@font-face
	{font-family:"\@黑体";
	panose-1:2 1 6 9 6 1 1 1 1 1;}
@font-face
	{font-family:"\@宋体";
	panose-1:2 1 6 0 3 1 1 1 1 1;}
@font-face
	{font-family:"\@方正小标宋简体";}
 /* Style Definitions */
 p.MsoNormal, li.MsoNormal, div.MsoNormal
	{margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
h1
	{mso-style-link:"标题 1 Char";
	margin-top:17.0pt;
	margin-right:0cm;
	margin-bottom:16.5pt;
	margin-left:7.2pt;
	text-align:center;
	text-indent:-7.2pt;
	page-break-after:avoid;
	font-size:22.0pt;
	font-family:宋体;
	font-weight:bold;}
h2
	{mso-style-link:"标题 2 Char";
	margin-top:13.0pt;
	margin-right:0cm;
	margin-bottom:13.0pt;
	margin-left:0cm;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:0cm;
	page-break-after:avoid;
	font-size:16.0pt;
	font-family:"Arial","sans-serif";
	font-weight:bold;}
h3
	{mso-style-link:"标题 3 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:0cm;
	page-break-after:avoid;
	font-size:14.0pt;
	font-family:"Arial","sans-serif";
	font-weight:bold;}
h4
	{mso-style-link:"标题 4 Char";
	margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:28.8pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-28.8pt;
	page-break-after:avoid;
	font-size:12.0pt;
	font-family:"Arial","sans-serif";
	font-weight:bold;}
h5
	{mso-style-link:"标题 5 Char";
	margin-top:14.0pt;
	margin-right:0cm;
	margin-bottom:14.5pt;
	margin-left:36.0pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-36.0pt;
	line-height:156%;
	page-break-after:avoid;
	font-size:14.0pt;
	font-family:宋体;
	font-weight:bold;}
h6
	{mso-style-link:"标题 6 Char";
	margin-top:12.0pt;
	margin-right:0cm;
	margin-bottom:3.2pt;
	margin-left:43.2pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-43.2pt;
	line-height:133%;
	page-break-after:avoid;
	font-size:12.0pt;
	font-family:"Arial","sans-serif";
	font-weight:bold;}
p.MsoHeading7, li.MsoHeading7, div.MsoHeading7
	{mso-style-link:"标题 7 Char";
	margin-top:12.0pt;
	margin-right:0cm;
	margin-bottom:3.2pt;
	margin-left:50.4pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-50.4pt;
	line-height:133%;
	page-break-after:avoid;
	font-size:12.0pt;
	font-family:宋体;
	font-weight:bold;}
p.MsoHeading8, li.MsoHeading8, div.MsoHeading8
	{mso-style-link:"标题 8 Char";
	margin-top:12.0pt;
	margin-right:0cm;
	margin-bottom:3.2pt;
	margin-left:57.6pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-72.0pt;
	line-height:133%;
	page-break-after:avoid;
	font-size:12.0pt;
	font-family:"Arial","sans-serif";}
p.MsoHeading9, li.MsoHeading9, div.MsoHeading9
	{mso-style-link:"标题 9 Char";
	margin-top:12.0pt;
	margin-right:0cm;
	margin-bottom:3.2pt;
	margin-left:64.8pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-79.2pt;
	line-height:133%;
	page-break-after:avoid;
	font-size:10.5pt;
	font-family:"Arial","sans-serif";}
p.MsoIndex1, li.MsoIndex1, div.MsoIndex1
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:10.5pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-10.5pt;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoIndex2, li.MsoIndex2, div.MsoIndex2
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:21.0pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-10.5pt;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoIndex3, li.MsoIndex3, div.MsoIndex3
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:31.5pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-10.5pt;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoIndex4, li.MsoIndex4, div.MsoIndex4
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:42.0pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-10.5pt;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoIndex5, li.MsoIndex5, div.MsoIndex5
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:52.5pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-10.5pt;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoIndex6, li.MsoIndex6, div.MsoIndex6
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:63.0pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-10.5pt;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoIndex7, li.MsoIndex7, div.MsoIndex7
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:73.5pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-10.5pt;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoIndex8, li.MsoIndex8, div.MsoIndex8
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:84.0pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-10.5pt;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoIndex9, li.MsoIndex9, div.MsoIndex9
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:94.5pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-10.5pt;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoToc1, li.MsoToc1, div.MsoToc1
	{margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;
	font-weight:bold;}
p.MsoToc2, li.MsoToc2, div.MsoToc2
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:21.0pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoToc3, li.MsoToc3, div.MsoToc3
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:42.0pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoToc4, li.MsoToc4, div.MsoToc4
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:31.5pt;
	margin-bottom:.0001pt;
	font-size:9.0pt;
	font-family:宋体;}
p.MsoToc5, li.MsoToc5, div.MsoToc5
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:42.0pt;
	margin-bottom:.0001pt;
	font-size:9.0pt;
	font-family:宋体;}
p.MsoToc6, li.MsoToc6, div.MsoToc6
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:52.5pt;
	margin-bottom:.0001pt;
	font-size:9.0pt;
	font-family:宋体;}
p.MsoToc7, li.MsoToc7, div.MsoToc7
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:63.0pt;
	margin-bottom:.0001pt;
	font-size:9.0pt;
	font-family:宋体;}
p.MsoToc8, li.MsoToc8, div.MsoToc8
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:73.5pt;
	margin-bottom:.0001pt;
	font-size:9.0pt;
	font-family:宋体;}
p.MsoToc9, li.MsoToc9, div.MsoToc9
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:84.0pt;
	margin-bottom:.0001pt;
	font-size:9.0pt;
	font-family:宋体;}
p.MsoFootnoteText, li.MsoFootnoteText, div.MsoFootnoteText
	{mso-style-link:"脚注文本 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	layout-grid-mode:char;
	font-size:9.0pt;
	font-family:宋体;}
p.MsoCommentText, li.MsoCommentText, div.MsoCommentText
	{mso-style-link:"批注文字 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoHeader, li.MsoHeader, div.MsoHeader
	{mso-style-link:"页眉 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	layout-grid-mode:char;
	border:none;
	padding:0cm;
	font-size:9.0pt;
	font-family:宋体;}
p.MsoFooter, li.MsoFooter, div.MsoFooter
	{mso-style-link:"页脚 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	layout-grid-mode:char;
	font-size:9.0pt;
	font-family:宋体;}
p.MsoIndexHeading, li.MsoIndexHeading, div.MsoIndexHeading
	{mso-style-name:"索引标题\,索引类目\,索引类目1\,索引类目2";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoCaption, li.MsoCaption, div.MsoCaption
	{margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:"Arial","sans-serif";}
p.MsoTof, li.MsoTof, div.MsoTof
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:42.0pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-21.0pt;
	font-size:10.5pt;
	font-family:宋体;}
span.MsoFootnoteReference
	{vertical-align:super;}
p.MsoList, li.MsoList, div.MsoList
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:21.0pt;
	margin-bottom:.0001pt;
	text-align:center;
	text-indent:-21.0pt;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoList2, li.MsoList2, div.MsoList2
	{margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoList4, li.MsoList4, div.MsoList4
	{margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoDate, li.MsoDate, div.MsoDate
	{mso-style-link:"日期 Char";
	margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:5.0pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
a:link, span.MsoHyperlink
	{mso-style-name:"超链接\,超级链接";
	color:blue;
	text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
	{color:purple;
	text-decoration:underline;}
p
	{mso-style-name:"普通\(网站\)\,普通 \(Web\)\,普通 \(Web\)1\,普通 \(Web\)2\,普通 \(Web\)3";
	margin-right:0cm;
	margin-left:0cm;
	font-size:12.0pt;
	font-family:宋体;}
pre
	{mso-style-name:"HTML 预设格式\,HTML 预先格式化\,HTML 预先格式化1\,HTML 预先格式化2\,HTML 预先格式化3";
	mso-style-link:"HTML 预设格式 Char\,HTML 预先格式化 Char\,HTML 预先格式化1 Char\,HTML 预先格式化2 Char\,HTML 预先格式化3 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	font-size:12.0pt;
	font-family:宋体;}
tt
	{font-family:黑体;}
p.MsoCommentSubject, li.MsoCommentSubject, div.MsoCommentSubject
	{mso-style-link:"批注主题 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	font-size:10.5pt;
	font-family:宋体;
	font-weight:bold;}
p.MsoAcetate, li.MsoAcetate, div.MsoAcetate
	{mso-style-link:"批注框文本 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:9.0pt;
	font-family:宋体;}
p.1, li.1, div.1
	{mso-style-name:样式1;
	margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:21.0pt;
	margin-bottom:.0001pt;
	text-align:center;
	text-indent:-21.0pt;
	font-size:10.5pt;
	font-family:宋体;}
p.a, li.a, div.a
	{mso-style-name:代码程序;
	mso-style-link:"代码程序 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	font-size:10.0pt;
	font-family:宋体;}
span.Char
	{mso-style-name:"代码程序 Char";
	mso-style-link:代码程序;
	font-family:宋体;}
p.a0, li.a0, div.a0
	{mso-style-name:图说明;
	mso-style-link:"图说明 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
span.Char0
	{mso-style-name:"图说明 Char";
	mso-style-link:图说明;
	font-family:宋体;}
p.0, li.0, div.0
	{mso-style-name:封面0;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:36.0pt;
	font-family:宋体;
	font-weight:bold;}
p.10, li.10, div.10
	{mso-style-name:封面1;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:18.0pt;
	font-family:宋体;
	font-weight:bold;}
p.11, li.11, div.11
	{mso-style-name:非标题1;
	margin-top:7.8pt;
	margin-right:0cm;
	margin-bottom:7.8pt;
	margin-left:0cm;
	text-align:center;
	font-size:22.0pt;
	font-family:宋体;
	font-weight:bold;}
p.a1, li.a1, div.a1
	{mso-style-name:文本居中;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.3CharChar, li.3CharChar, div.3CharChar
	{mso-style-name:"图中文字3 Char Char";
	mso-style-link:"图中文字3 Char Char Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	line-height:9.0pt;
	font-size:8.0pt;
	font-family:宋体;}
span.3CharCharChar
	{mso-style-name:"图中文字3 Char Char Char";
	mso-style-link:"图中文字3 Char Char";
	font-family:宋体;}
p.post, li.post, div.post
	{mso-style-name:邮件post;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:right;
	line-height:11.0pt;
	font-size:10.5pt;
	font-family:宋体;}
p.3, li.3, div.3
	{mso-style-name:图中字体3;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
span.3CharChar1CharCharChar
	{mso-style-name:"图中文字3 Char Char1 Char Char Char";
	font-family:宋体;}
span.3CharChar1CharChar
	{mso-style-name:"图中文字3 Char Char1 Char Char";
	font-family:宋体;}
p.5Char, li.5Char, div.5Char
	{mso-style-name:"图中文字5号 Char";
	mso-style-link:"图中文字5号 Char Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
span.5CharChar
	{mso-style-name:"图中文字5号 Char Char";
	mso-style-link:"图中文字5号 Char";
	font-family:宋体;}
p.5CharChar0, li.5CharChar0, div.5CharChar0
	{mso-style-name:"图中文字小5号 Char Char";
	mso-style-link:"图中文字小5号 Char Char Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:9.0pt;
	font-family:宋体;}
span.5CharCharChar
	{mso-style-name:"图中文字小5号 Char Char Char";
	mso-style-link:"图中文字小5号 Char Char";
	font-family:宋体;}
p.5Char0, li.5Char0, div.5Char0
	{mso-style-name:"图中文字小5号 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:9.0pt;
	font-family:宋体;}
p.5, li.5, div.5
	{mso-style-name:图中文字小5号;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	layout-grid-mode:char;
	font-size:9.0pt;
	font-family:宋体;}
p.2, li.2, div.2
	{mso-style-name:代码程序2;
	margin:0cm;
	margin-bottom:.0001pt;
	font-size:10.0pt;
	font-family:宋体;}
p.20, li.20, div.20
	{mso-style-name:图说明2;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.21, li.21, div.21
	{mso-style-name:文本居中2;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.3CharCharCharCharChar, li.3CharCharCharCharChar, div.3CharCharCharCharChar
	{mso-style-name:"图中文字3 Char Char Char Char Char";
	mso-style-link:"图中文字3 Char Char Char Char Char Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	line-height:9.0pt;
	font-size:8.0pt;
	font-family:宋体;}
span.3CharCharCharCharCharChar
	{mso-style-name:"图中文字3 Char Char Char Char Char Char";
	mso-style-link:"图中文字3 Char Char Char Char Char";
	font-family:宋体;}
p.a2, li.a2, div.a2
	{mso-style-name:图居中;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.110, li.110, div.110
	{mso-style-name:"样式 标题 1 + 居中1";
	margin-right:0cm;
	margin-left:0cm;
	text-align:center;
	page-break-after:avoid;
	font-size:22.0pt;
	font-family:宋体;
	font-weight:bold;}
span.1Char
	{mso-style-name:"标题 1 Char";
	mso-style-link:"标题 1";
	font-weight:bold;}
p.22, li.22, div.22
	{mso-style-name:"样式 列表 2 + 居中";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.23, li.23, div.23
	{mso-style-name:列表2;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.50, li.50, div.50
	{mso-style-name:图中文字5号;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.111, li.111, div.111
	{mso-style-name:样式11;
	margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:21.0pt;
	margin-bottom:.0001pt;
	text-align:center;
	text-indent:-21.0pt;
	font-size:10.5pt;
	font-family:宋体;}
p.12, li.12, div.12
	{mso-style-name:代码程序1;
	margin:0cm;
	margin-bottom:.0001pt;
	font-size:10.0pt;
	font-family:宋体;}
p.13, li.13, div.13
	{mso-style-name:图说明1;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.01, li.01, div.01
	{mso-style-name:封面01;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:36.0pt;
	font-family:宋体;
	font-weight:bold;}
p.112, li.112, div.112
	{mso-style-name:封面11;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:18.0pt;
	font-family:宋体;
	font-weight:bold;}
p.113, li.113, div.113
	{mso-style-name:非标题11;
	margin-top:7.8pt;
	margin-right:0cm;
	margin-bottom:7.8pt;
	margin-left:0cm;
	text-align:center;
	font-size:22.0pt;
	font-family:宋体;
	font-weight:bold;}
p.14, li.14, div.14
	{mso-style-name:文本居中1;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.3Char1, li.3Char1, div.3Char1
	{mso-style-name:"图中文字3 Char1";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	line-height:9.0pt;
	font-size:8.0pt;
	font-family:宋体;}
p.post1, li.post1, div.post1
	{mso-style-name:邮件post1;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:right;
	line-height:11.0pt;
	font-size:10.5pt;
	font-family:宋体;}
p.31, li.31, div.31
	{mso-style-name:图中字体31;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
p.5Char1, li.5Char1, div.5Char1
	{mso-style-name:"图中文字5号 Char1";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.5CharChar1, li.5CharChar1, div.5CharChar1
	{mso-style-name:"图中文字小5号 Char Char1";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:9.0pt;
	font-family:宋体;}
p.5Char10, li.5Char10, div.5Char10
	{mso-style-name:"图中文字小5号 Char1";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:9.0pt;
	font-family:宋体;}
p.51, li.51, div.51
	{mso-style-name:图中文字小5号1;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:9.0pt;
	font-family:宋体;}
p.120, li.120, div.120
	{mso-style-name:样式12;
	margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:21.0pt;
	margin-bottom:.0001pt;
	text-align:center;
	text-indent:-21.0pt;
	font-size:10.5pt;
	font-family:宋体;}
p.02, li.02, div.02
	{mso-style-name:封面02;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:36.0pt;
	font-family:宋体;
	font-weight:bold;}
p.121, li.121, div.121
	{mso-style-name:封面12;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:18.0pt;
	font-family:宋体;
	font-weight:bold;}
p.122, li.122, div.122
	{mso-style-name:非标题12;
	margin-top:7.8pt;
	margin-right:0cm;
	margin-bottom:7.8pt;
	margin-left:0cm;
	text-align:center;
	font-size:22.0pt;
	font-family:宋体;
	font-weight:bold;}
p.3Char2, li.3Char2, div.3Char2
	{mso-style-name:"图中文字3 Char2";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	line-height:9.0pt;
	font-size:8.0pt;
	font-family:宋体;}
p.post2, li.post2, div.post2
	{mso-style-name:邮件post2;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:right;
	line-height:11.0pt;
	font-size:10.5pt;
	font-family:宋体;}
p.32, li.32, div.32
	{mso-style-name:图中字体32;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
p.5Char2, li.5Char2, div.5Char2
	{mso-style-name:"图中文字小5号 Char2";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:9.0pt;
	font-family:宋体;}
p.52, li.52, div.52
	{mso-style-name:图中文字小5号2;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:9.0pt;
	font-family:宋体;}
p.3CharCharCharChar, li.3CharCharCharChar, div.3CharCharCharChar
	{mso-style-name:"图中文字3 Char Char Char Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	line-height:9.0pt;
	font-size:8.0pt;
	font-family:宋体;}
p.130, li.130, div.130
	{mso-style-name:样式13;
	margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:21.0pt;
	margin-bottom:.0001pt;
	text-align:center;
	text-indent:-21.0pt;
	font-size:10.5pt;
	font-family:宋体;}
p.30, li.30, div.30
	{mso-style-name:代码程序3;
	margin:0cm;
	margin-bottom:.0001pt;
	font-size:10.0pt;
	font-family:宋体;}
p.03, li.03, div.03
	{mso-style-name:封面03;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:36.0pt;
	font-family:宋体;
	font-weight:bold;}
p.131, li.131, div.131
	{mso-style-name:封面13;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:18.0pt;
	font-family:宋体;
	font-weight:bold;}
p.132, li.132, div.132
	{mso-style-name:非标题13;
	margin-top:7.8pt;
	margin-right:0cm;
	margin-bottom:7.8pt;
	margin-left:0cm;
	text-align:center;
	font-size:22.0pt;
	font-family:宋体;
	font-weight:bold;}
p.33, li.33, div.33
	{mso-style-name:文本居中3;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.3Char3, li.3Char3, div.3Char3
	{mso-style-name:"图中文字3 Char3";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	line-height:9.0pt;
	font-size:8.0pt;
	font-family:宋体;}
p.post3, li.post3, div.post3
	{mso-style-name:邮件post3;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:right;
	line-height:11.0pt;
	font-size:10.5pt;
	font-family:宋体;}
p.330, li.330, div.330
	{mso-style-name:图中字体33;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
p.5Char20, li.5Char20, div.5Char20
	{mso-style-name:"图中文字5号 Char2";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.5CharChar2, li.5CharChar2, div.5CharChar2
	{mso-style-name:"图中文字小5号 Char Char2";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:9.0pt;
	font-family:宋体;}
p.5Char3, li.5Char3, div.5Char3
	{mso-style-name:"图中文字小5号 Char3";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:9.0pt;
	font-family:宋体;}
p.53, li.53, div.53
	{mso-style-name:图中文字小5号3;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:9.0pt;
	font-family:宋体;}
p.3Char, li.3Char, div.3Char
	{mso-style-name:"图中文字3 Char";
	mso-style-link:"图中文字3 Char Char5";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	line-height:9.0pt;
	font-size:8.0pt;
	font-family:宋体;}
span.3CharChar5
	{mso-style-name:"图中文字3 Char Char5";
	mso-style-link:"图中文字3 Char";
	font-family:宋体;}
p.54, li.54, div.54
	{mso-style-name:图中文字小5紧密;
	margin:0cm;
	margin-bottom:.0001pt;
	line-height:9.0pt;
	text-autospace:ideograph-numeric;
	font-size:9.0pt;
	font-family:宋体;}
p.24, li.24, div.24
	{mso-style-name:居中2号粗宋体;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:22.0pt;
	font-family:宋体;
	font-weight:bold;}
p.15, li.15, div.15
	{mso-style-name:"样式 标题 1 + 居中";
	margin-top:17.0pt;
	margin-right:0cm;
	margin-bottom:16.5pt;
	margin-left:0cm;
	text-align:center;
	page-break-after:avoid;
	font-size:22.0pt;
	font-family:宋体;
	font-weight:bold;}
p.25, li.25, div.25
	{mso-style-name:"样式 标题 2 + 行距\: 单倍行距";
	margin-top:13.0pt;
	margin-right:0cm;
	margin-bottom:13.0pt;
	margin-left:28.9pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-28.9pt;
	page-break-after:avoid;
	font-size:16.0pt;
	font-family:"Arial","sans-serif";
	font-weight:bold;}
span.2Char
	{mso-style-name:"标题 2 Char";
	mso-style-link:"标题 2";
	font-family:"Arial","sans-serif";
	font-weight:bold;}
p.34, li.34, div.34
	{mso-style-name:列表3;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.35, li.35, div.35
	{mso-style-name:表3;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.4, li.4, div.4
	{mso-style-name:图说明4;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.40, li.40, div.40
	{mso-style-name:列表4;
	margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:21.0pt;
	margin-bottom:.0001pt;
	text-align:center;
	text-indent:-21.0pt;
	font-size:10.5pt;
	font-family:宋体;}
p.41, li.41, div.41
	{mso-style-name:表4;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.55, li.55, div.55
	{mso-style-name:图说明5;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.56, li.56, div.56
	{mso-style-name:列表5;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.57, li.57, div.57
	{mso-style-name:表5;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.6, li.6, div.6
	{mso-style-name:列表6;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.60, li.60, div.60
	{mso-style-name:表6;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.61, li.61, div.61
	{mso-style-name:图说明6;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.7, li.7, div.7
	{mso-style-name:列表7;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.70, li.70, div.70
	{mso-style-name:图说明7;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.71, li.71, div.71
	{mso-style-name:表7;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.8, li.8, div.8
	{mso-style-name:列表8;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.9, li.9, div.9
	{mso-style-name:列表9;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.90, li.90, div.90
	{mso-style-name:图说明9;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.100, li.100, div.100
	{mso-style-name:列表10;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.101, li.101, div.101
	{mso-style-name:图说明10;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.114, li.114, div.114
	{mso-style-name:列表11;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.115, li.115, div.115
	{mso-style-name:图说明11;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.116, li.116, div.116
	{mso-style-name:表11;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.123, li.123, div.123
	{mso-style-name:列表12;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.124, li.124, div.124
	{mso-style-name:图说明12;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.133, li.133, div.133
	{mso-style-name:图说明13;
	mso-style-link:"图说明13 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
span.13Char
	{mso-style-name:"图说明13 Char";
	mso-style-link:图说明13;
	font-family:宋体;}
p.134, li.134, div.134
	{mso-style-name:列表13;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.26, li.26, div.26
	{mso-style-name:附录2;
	margin-top:13.0pt;
	margin-right:0cm;
	margin-bottom:13.0pt;
	margin-left:0cm;
	text-align:justify;
	text-justify:inter-ideograph;
	page-break-after:avoid;
	font-size:16.0pt;
	font-family:"Arial","sans-serif";
	font-weight:bold;}
p.36, li.36, div.36
	{mso-style-name:附录3;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	page-break-after:avoid;
	font-size:14.0pt;
	font-family:"Arial","sans-serif";
	font-weight:bold;}
span.3Char0
	{mso-style-name:"标题 3 Char";
	mso-style-link:"标题 3";
	font-family:"Arial","sans-serif";
	font-weight:bold;}
p.16, li.16, div.16
	{mso-style-name:附录1;
	margin-top:17.0pt;
	margin-right:0cm;
	margin-bottom:16.5pt;
	margin-left:0cm;
	text-align:center;
	page-break-after:avoid;
	font-size:22.0pt;
	font-family:宋体;
	font-weight:bold;}
p.17, li.17, div.17
	{mso-style-name:附录表1;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.42, li.42, div.42
	{mso-style-name:附录4;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	page-break-after:avoid;
	font-size:12.0pt;
	font-family:"Arial","sans-serif";
	font-weight:bold;}
span.4Char
	{mso-style-name:"标题 4 Char";
	mso-style-link:"标题 4";
	font-family:"Arial","sans-serif";
	font-weight:bold;}
p.a3, li.a3, div.a3
	{mso-style-name:附录图说明;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.27, li.27, div.27
	{mso-style-name:序标题2;
	margin-top:13.0pt;
	margin-right:0cm;
	margin-bottom:13.0pt;
	margin-left:28.8pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-28.8pt;
	page-break-after:avoid;
	font-size:16.0pt;
	font-family:"Arial","sans-serif";
	font-weight:bold;}
p.a4, li.a4, div.a4
	{mso-style-name:参考标题;
	margin-top:7.8pt;
	margin-right:0cm;
	margin-bottom:7.8pt;
	margin-left:0cm;
	text-align:center;
	page-break-after:avoid;
	font-size:22.0pt;
	font-family:宋体;
	font-weight:bold;}
p.18, li.18, div.18
	{mso-style-name:索引标题1;
	margin-top:7.8pt;
	margin-right:0cm;
	margin-bottom:7.8pt;
	margin-left:0cm;
	text-align:center;
	page-break-after:avoid;
	font-size:22.0pt;
	font-family:宋体;
	font-weight:bold;}
p.19, li.19, div.19
	{mso-style-name:列表1;
	margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:21.25pt;
	margin-bottom:.0001pt;
	text-align:center;
	text-indent:-21.25pt;
	font-size:10.5pt;
	font-family:宋体;}
p.1a, li.1a, div.1a
	{mso-style-name:表1;
	margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:21.25pt;
	margin-bottom:.0001pt;
	text-align:center;
	text-indent:-21.25pt;
	font-size:10.5pt;
	font-family:宋体;}
p.37, li.37, div.37
	{mso-style-name:图说明3;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.62, li.62, div.62
	{mso-style-name:表中字体6号;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	layout-grid-mode:char;
	font-size:7.5pt;
	font-family:宋体;}
p.a5, li.a5, div.a5
	{mso-style-name:正文代码;
	mso-style-link:"正文代码 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
span.Char1
	{mso-style-name:"正文代码 Char";
	mso-style-link:正文代码;
	font-family:宋体;}
p.43, li.43, div.43
	{mso-style-name:"样式 标题 4 +";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	page-break-after:avoid;
	font-size:12.0pt;
	font-family:"Arial","sans-serif";
	font-weight:bold;}
p.140, li.140, div.140
	{mso-style-name:表14;
	margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:21.25pt;
	margin-bottom:.0001pt;
	text-align:center;
	text-indent:-21.25pt;
	font-size:10.5pt;
	font-family:宋体;}
p.141, li.141, div.141
	{mso-style-name:图说明14;
	mso-style-link:"图说明14 Char";
	margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:21.25pt;
	margin-bottom:.0001pt;
	text-align:center;
	text-indent:-21.25pt;
	font-size:10.5pt;
	font-family:宋体;}
span.14Char
	{mso-style-name:"图说明14 Char";
	mso-style-link:图说明14;
	font-family:宋体;}
p.a6, li.a6, div.a6
	{mso-style-name:文件目录表;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
p.a7, li.a7, div.a7
	{mso-style-name:"样式 正文 +";
	mso-style-link:"样式 正文 + Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
span.Char2
	{mso-style-name:"样式 正文 + Char";
	mso-style-link:"样式 正文 +";
	font-family:"Times New Roman","serif";}
p.a8, li.a8, div.a8
	{mso-style-name:表格题注;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.a9, li.a9, div.a9
	{mso-style-name:列表题注;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:"Arial","sans-serif";}
p.aa, li.aa, div.aa
	{mso-style-name:图题注;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:"Arial","sans-serif";}
p.ab, li.ab, div.ab
	{mso-style-name:程序题注;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:"Arial","sans-serif";}
p.ac, li.ac, div.ac
	{mso-style-name:框中文字;
	margin-top:0cm;
	margin-right:21.0pt;
	margin-bottom:0cm;
	margin-left:21.0pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	border:none;
	padding:0cm;
	font-size:9.0pt;
	font-family:宋体;}
p.125, li.125, div.125
	{mso-style-name:"样式 标题 1 + 居中2";
	margin-top:17.0pt;
	margin-right:0cm;
	margin-bottom:16.5pt;
	margin-left:0cm;
	text-align:center;
	page-break-after:avoid;
	font-size:22.0pt;
	font-family:宋体;
	font-weight:bold;}
p.ad, li.ad, div.ad
	{mso-style-name:"样式 题注 + 宋体 五号 居中";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:黑体;}
p.1b, li.1b, div.1b
	{mso-style-name:序标题1;
	margin-top:17.0pt;
	margin-right:0cm;
	margin-bottom:16.5pt;
	margin-left:0cm;
	line-height:240%;
	page-break-after:avoid;
	font-size:16.0pt;
	font-family:宋体;
	font-weight:bold;}
p.38, li.38, div.38
	{mso-style-name:序标题3;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	page-break-after:avoid;
	font-size:12.0pt;
	font-family:方正小标宋简体;}
p.63, li.63, div.63
	{mso-style-name:表中文字6号;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:7.5pt;
	font-family:宋体;}
p.64, li.64, div.64
	{mso-style-name:图中文字6号左对齐;
	margin:0cm;
	margin-bottom:.0001pt;
	line-height:10.0pt;
	layout-grid-mode:char;
	font-size:7.5pt;
	font-family:宋体;}
p.65, li.65, div.65
	{mso-style-name:图中文字6号;
	mso-style-link:"图中文字6号 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	line-height:10.0pt;
	layout-grid-mode:char;
	font-size:7.5pt;
	font-family:宋体;}
span.6Char
	{mso-style-name:"图中文字6号 Char";
	mso-style-link:图中文字6号;
	font-family:宋体;}
p.ae, li.ae, div.ae
	{mso-style-name:图标;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
p.28, li.28, div.28
	{mso-style-name:图标2;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
p.af, li.af, div.af
	{mso-style-name:习题标题;
	margin-top:6.0pt;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	page-break-after:avoid;
	font-size:14.0pt;
	font-family:黑体;}
p.1c, li.1c, div.1c
	{mso-style-name:部分编号1;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:16.0pt;
	font-family:宋体;}
p.af0, li.af0, div.af0
	{mso-style-name:表标题;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:"Arial","sans-serif";}
p.af1, li.af1, div.af1
	{mso-style-name:"样式 题注 + 居中";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.ListTitle, li.ListTitle, div.ListTitle
	{mso-style-name:ListTitle;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:"Arial","sans-serif";}
p.FigureTitle, li.FigureTitle, div.FigureTitle
	{mso-style-name:FigureTitle;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:"Arial","sans-serif";}
p.TableTitle, li.TableTitle, div.TableTitle
	{mso-style-name:TableTitle;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:"Arial","sans-serif";}
p.ProgramTitle, li.ProgramTitle, div.ProgramTitle
	{mso-style-name:ProgramTitle;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:"Arial","sans-serif";}
p.RightText, li.RightText, div.RightText
	{mso-style-name:RightText;
	margin-top:0cm;
	margin-right:21.0pt;
	margin-bottom:0cm;
	margin-left:42.0pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	border:none;
	padding:0cm;
	font-size:9.0pt;
	font-family:宋体;}
p.af2, li.af2, div.af2
	{mso-style-name:表中文字小五;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:9.0pt;
	font-family:宋体;}
p.af3, li.af3, div.af3
	{mso-style-name:关键词;
	mso-style-link:"关键词 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
span.Char3
	{mso-style-name:"关键词 Char";
	mso-style-link:关键词;
	font-family:宋体;}
p.af4, li.af4, div.af4
	{mso-style-name:文件名;
	mso-style-link:"文件名 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
span.Char4
	{mso-style-name:"文件名 Char";
	mso-style-link:文件名;
	font-family:宋体;}
p.af5, li.af5, div.af5
	{mso-style-name:选项;
	mso-style-link:"选项 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
span.Char5
	{mso-style-name:"选项 Char";
	mso-style-link:选项;
	font-family:宋体;}
p.af6, li.af6, div.af6
	{mso-style-name:命令行;
	mso-style-link:"命令行 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
span.Char6
	{mso-style-name:"命令行 Char";
	mso-style-link:命令行;
	font-family:宋体;}
p.af7, li.af7, div.af7
	{mso-style-name:函数名;
	mso-style-link:"函数名 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
span.Char7
	{mso-style-name:"函数名 Char";
	mso-style-link:函数名;
	font-family:宋体;}
p.af8, li.af8, div.af8
	{mso-style-name:寄存器名;
	mso-style-link:"寄存器名 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
span.Char8
	{mso-style-name:"寄存器名 Char";
	mso-style-link:寄存器名;
	font-family:"Times New Roman","serif";}
p.af9, li.af9, div.af9
	{mso-style-name:变量名;
	mso-style-link:"变量名 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
span.Char9
	{mso-style-name:"变量名 Char";
	mso-style-link:变量名;
	font-family:宋体;}
p.58, li.58, div.58
	{mso-style-name:图中文字小5号左;
	margin:0cm;
	margin-bottom:.0001pt;
	font-size:9.0pt;
	font-family:宋体;}
p.59, li.59, div.59
	{mso-style-name:图中文字小5号靠左;
	margin:0cm;
	margin-bottom:.0001pt;
	layout-grid-mode:char;
	font-size:9.0pt;
	font-family:宋体;}
p.926, li.926, div.926
	{mso-style-name:"样式 代码程序 + 左侧\:  9\.26 厘米";
	margin:0cm;
	margin-bottom:.0001pt;
	layout-grid-mode:char;
	font-size:10.0pt;
	font-family:宋体;}
span.5Char4
	{mso-style-name:"标题 5 Char";
	mso-style-link:"标题 5";
	font-weight:bold;}
span.6Char0
	{mso-style-name:"标题 6 Char";
	mso-style-link:"标题 6";
	font-family:"Arial","sans-serif";
	font-weight:bold;}
span.7Char
	{mso-style-name:"标题 7 Char";
	mso-style-link:"标题 7";
	font-weight:bold;}
span.8Char
	{mso-style-name:"标题 8 Char";
	mso-style-link:"标题 8";
	font-family:"Arial","sans-serif";}
span.9Char
	{mso-style-name:"标题 9 Char";
	mso-style-link:"标题 9";
	font-family:"Arial","sans-serif";}
span.Chara
	{mso-style-name:"脚注文本 Char";
	mso-style-link:脚注文本;
	font-family:宋体;}
span.Charb
	{mso-style-name:"批注文字 Char";
	mso-style-link:批注文字;
	font-family:宋体;}
span.Charc
	{mso-style-name:"页眉 Char";
	mso-style-link:页眉;
	font-family:宋体;}
span.Chard
	{mso-style-name:"页脚 Char";
	mso-style-link:页脚;
	font-family:宋体;}
span.Chare
	{mso-style-name:"日期 Char";
	mso-style-link:日期;
	font-family:宋体;}
span.HTMLChar
	{mso-style-name:"HTML 预设格式 Char\,HTML 预先格式化 Char\,HTML 预先格式化1 Char\,HTML 预先格式化2 Char\,HTML 预先格式化3 Char";
	mso-style-link:"HTML 预设格式\,HTML 预先格式化\,HTML 预先格式化1\,HTML 预先格式化2\,HTML 预先格式化3";
	font-family:宋体;}
span.Charf
	{mso-style-name:"批注主题 Char";
	mso-style-link:批注主题;
	font-family:宋体;
	font-weight:bold;}
span.Charf0
	{mso-style-name:"批注框文本 Char";
	mso-style-link:批注框文本;
	font-family:宋体;}
span.3CharChar1
	{mso-style-name:"图中文字3 Char Char1";
	font-family:宋体;}
span.3CharChar3
	{mso-style-name:"图中文字3 Char Char3";
	font-family:宋体;}
.MsoChpDefault
	{font-size:10.0pt;}
 /* Page Definitions */
 @page WordSection1
	{size:595.3pt 841.9pt;
	margin:72.0pt 54.0pt 72.0pt 54.0pt;
	layout-grid:15.6pt;}
div.WordSection1
	{page:WordSection1;}
 /* List Definitions */
 ol
	{margin-bottom:0cm;}
ul
	{margin-bottom:0cm;}
-->
</style>

</head>

<body lang=ZH-CN link=blue vlink=purple style='text-justify-trim:punctuation'>

<div class=WordSection1 style='layout-grid:15.6pt'>

<p class=ab><a name="_Toc53320652"><span style='font-family:黑体'>程序</span><span
lang=EN-US>13-1 linux/mm/memory.c</span></a></p>

<div class=a align=center style='text-align:center'><span lang=EN-US>

<hr size=4 width="100%" align=center>

</span></div>

<p class=a><span lang=EN-US>&nbsp; <u><span style='color:blue'>1</span></u> <b><i>/*</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp; <u><span style='color:blue'>2</span></u> <b><i>&nbsp;*&nbsp;
linux/mm/memory.c</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp; <u><span style='color:blue'>3</span></u> <b><i>&nbsp;*</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp; <u><span style='color:blue'>4</span></u> <b><i>&nbsp;*&nbsp;
(C) 1991&nbsp; Linus Torvalds</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp; <u><span style='color:blue'>5</span></u> <b><i>&nbsp;*/</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp; <u><span style='color:blue'>6</span></u> </span></p>

<p class=a><span lang=EN-US>&nbsp; <u><span style='color:blue'>7</span></u> <b><i>/*</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp; <u><span style='color:blue'>8</span></u> <b><i>&nbsp;*
demand-loading started 01.12.91 - seems it is high on the list of</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp; <u><span style='color:blue'>9</span></u> <b><i>&nbsp;*
things wanted, and it should be easy to implement. - Linus</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>10</span></u> <b><i>&nbsp;*/</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; /*</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>需求加载是从<span
lang=EN-US>91.12.1</span>开始编写的<span lang=EN-US> - </span>在程序编制表中似乎是最重要的程序，</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>并且应该是很容易编制的<span
lang=EN-US> - Linus</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; */</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>11</span></u> </span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>12</span></u> <b><i>/*</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>13</span></u> <b><i>&nbsp;*
Ok, demand-loading was easy, shared pages a little bit tricker. Shared</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>14</span></u> <b><i>&nbsp;*
pages started 02.12.91, seems to work. - Linus.</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>15</span></u> <b><i>&nbsp;*</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>16</span></u> <b><i>&nbsp;*
Tested sharing by executing about 30 /bin/sh: under the old kernel it</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>17</span></u> <b><i>&nbsp;*
would have taken more than the 6M I have free, but it worked well as</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>18</span></u> <b><i>&nbsp;*
far as I could see.</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>19</span></u> <b><i>&nbsp;*</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>20</span></u> <b><i>&nbsp;*
Also corrected some &quot;invalidate()&quot;s - I wasn't doing enough of them.</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>21</span></u> <b><i>&nbsp;*/</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; /*</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * OK</span>，需求加载是比较容易编写的，而共享页面却需要有点技巧。共享页面程序是</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * 91.12.2</span>开始编写的，好象能够工作<span
lang=EN-US> - Linus</span>。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; *</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>通过执行大约<span
lang=EN-US>30</span>个<span lang=EN-US>/bin/sh</span>对共享操作进行了测试：在老内核当中需要占用多于</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * 6M</span>的内存，而目前却不用。现在看来工作得很好。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; *</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>对<span
lang=EN-US>&quot;invalidate()&quot;</span>函数也进行了修正<span lang=EN-US> - </span>在这方面我还做的不够。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; */</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>22</span></u> </span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>23</span></u> <b><i>/*</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>24</span></u> <b><i>&nbsp;*
Real VM (paging to/from disk) started 18.12.91. Much more work and</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>25</span></u> <b><i>&nbsp;*
thought has to go into this. Oh, well..</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>26</span></u> <b><i>&nbsp;*
19.12.91&nbsp; -&nbsp; works, somewhat. Sometimes I get faults, don't know why.</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>27</span></u> <b><i>&nbsp;*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Found it. Everything seems to work now.</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>28</span></u> <b><i>&nbsp;*
20.12.91&nbsp; -&nbsp; Ok, making the swap-device changeable like the root.</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>29</span></u> <b><i>&nbsp;*/</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; /*</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * 91.12.18</span>开始编写真正的虚拟内存管理<span
lang=EN-US>VM</span>（交换页面到<span lang=EN-US>/</span>从磁盘）。需要对此</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>考虑很多并且需要作很多工作。呵呵，也只能这样了。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * 91.12.19&nbsp; -&nbsp; </span>在某种程度上可以工作了，但有时会出错，不知道怎么回事。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;
*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span>找到错误了，现在好像一切都能工作了。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * 91.12.20&nbsp; -&nbsp;
OK</span>，把交换设备修改成可更改的了，就像根文件设备那样。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; */</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>30</span></u> </span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>31</span></u>
#include &lt;signal.h&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // </span>信号头文件。定义信号符号常量，信号结构及信号函数原型。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>32</span></u> </span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>33</span></u>
#include &lt;asm/system.h&gt;&nbsp;&nbsp; // </span>系统头文件。定义设置或修改描述符<span
lang=EN-US>/</span>中断门等嵌入汇编宏。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>34</span></u> </span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>35</span></u>
#include &lt;linux/sched.h&gt;&nbsp; // </span>调度程序头文件，定义任务结构<span lang=EN-US>task_struct</span>、任务<span
lang=EN-US>0</span>的数据。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>36</span></u>
#include &lt;linux/head.h&gt;&nbsp;&nbsp; // head</span>头文件，定义段描述符的简单结构，和几个选择符常量。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>37</span></u>
#include &lt;linux/kernel.h&gt; // </span>内核头文件。含有一些内核常用函数的原形定义。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>38</span></u> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // CODE_SPACE(addr) ((((addr)+0xfff)&amp;~0xfff)&lt;current-&gt;start_code+current-&gt;end_code)</span>。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>该宏用于判断给定线性地址是否位于当前进程的代码段中，“<span
lang=EN-US>(((addr)+4095)&amp;~4095)</span>”用于</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>取得线性地址<span
lang=EN-US>addr</span>所在内存页面的末端地址。参见<span lang=EN-US>265</span>行。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>39</span></u>
#define <u><span style='color:blue'>CODE_SPACE</span></u>(addr)
((((addr)+4095)&amp;~4095) &lt; \</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>40</span></u> <u><span
style='color:blue'>current</span></u>-&gt;start_code + <u><span
style='color:blue'>current</span></u>-&gt;end_code)</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>41</span></u> </span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>42</span></u>
unsigned long <u><span style='color:blue'>HIGH_MEMORY</span></u> = 0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>全局变量，存放实际物理内存最高端地址。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>43</span></u> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>从<span lang=EN-US>from</span>处复制<span
lang=EN-US>1</span>页内存到<span lang=EN-US>to</span>处（<span lang=EN-US>4K</span>字节）。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>44</span></u>
#define <u><span style='color:blue'>copy_page</span></u>(from,to) \</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>45</span></u>
__asm__(<i>&quot;cld ; rep ; movsl&quot;</i>::<i>&quot;S&quot;</i> (from),<i>&quot;D&quot;</i>
(to),<i>&quot;c&quot;</i> (1024):<i>&quot;cx&quot;</i>,<i>&quot;di&quot;</i>,<i>&quot;si&quot;</i>)</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>46</span></u> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>物理内存映射字节图（<span
lang=EN-US>1</span>字节代表<span lang=EN-US>1</span>页内存）。每个页面对应的字节用于标志页面当前被引用</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>（占用）次数。它最大可以映射<span
lang=EN-US>15Mb</span>的内存空间。在初始化函数<span lang=EN-US>mem_init()</span>中，对于不能用</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>作主内存区页面的位置均都预先被设置成<span
lang=EN-US>USED</span>（<span lang=EN-US>100</span>）。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>47</span></u>
unsigned char <u><span style='color:blue'>mem_map</span></u> [ <u><span
style='color:blue'>PAGING_PAGES</span></u> ] = {0,};</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>48</span></u> </span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>49</span></u> <b><i>/*</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>50</span></u> <b><i>&nbsp;*
Free a page of memory at physical address 'addr'. Used by</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>51</span></u> <b><i>&nbsp;*
'free_page_tables()'</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>52</span></u> <b><i>&nbsp;*/</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; /*</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>释放物理地址<span
lang=EN-US>'addr'</span>处的一页内存。用于函数<span lang=EN-US>'free_page_tables()'</span>。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; */</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; //// </span>释放物理地址<span
lang=EN-US>addr</span>开始的<span lang=EN-US>1</span>页面内存。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>物理地址<span lang=EN-US>1MB</span>以下的内存空间用于内核程序和缓冲，不作为分配页面的内存空间。因此</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>参数<span lang=EN-US>addr</span>需要大于<span
lang=EN-US>1MB</span>。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>53</span></u>
void <u><span style='color:blue'>free_page</span></u>(unsigned long addr)</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>54</span></u> {</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>首先判断参数给定的物理地址<span
lang=EN-US>addr</span>的合理性。如果物理地址<span lang=EN-US>addr</span>小于内存低端（<span
lang=EN-US>1MB</span>），</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>则表示在内核程序或高速缓冲中，对此不予处理。如果物理地址<span
lang=EN-US>addr &gt;= </span>系统所含物理</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>内存最高端，则显示出错信息并且内核停止工作。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>55</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (addr &lt; <u><span style='color:blue'>LOW_MEM</span></u>) return;</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>56</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (addr &gt;= <u><span style='color:blue'>HIGH_MEMORY</span></u>)</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>57</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>panic</span></u>(<i>&quot;trying to free
nonexistent page&quot;</i>);</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>如果对参数<span lang=EN-US>addr</span>验证通过，那么就根据这个物理地址换算出从内存低端开始计起的内存</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>页面号。页面号<span
lang=EN-US> = (addr – LOW_MEM)/4096</span>。可见页面号从<span lang=EN-US>0</span>号开始计起。此时<span
lang=EN-US>addr</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>中存放着页面号。如果该页面号对应的页面映射字节不等于<span
lang=EN-US>0</span>，则减<span lang=EN-US>1</span>返回。此时该映射</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>字节值应该为<span
lang=EN-US>0</span>，表示页面已释放。如果对应页面字节原本就是<span lang=EN-US>0</span>，表示该物理页面本来</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>就是空闲的，说明内核代码出问题。于是显示出错信息并停机。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>58</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
addr -= <u><span style='color:blue'>LOW_MEM</span></u>;</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>59</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
addr &gt;&gt;= 12;</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>60</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (<u><span style='color:blue'>mem_map</span></u>[addr]--) return;</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>61</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>mem_map</span></u>[addr]=0;</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>62</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>panic</span></u>(<i>&quot;trying to free free
page&quot;</i>);</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>63</span></u> }</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>64</span></u> </span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>65</span></u> <b><i>/*</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>66</span></u> <b><i>&nbsp;*
This function frees a continuos block of page tables, as needed</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>67</span></u> <b><i>&nbsp;*
by 'exit()'. As does copy_page_tables(), this handles only 4Mb blocks.</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>68</span></u> <b><i>&nbsp;*/</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; /*</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>下面函数释放页表连续的内存块，<span
lang=EN-US>'exit()'</span>需要该函数。与<span lang=EN-US>copy_page_tables()</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>类似，该函数仅处理<span
lang=EN-US>4Mb</span>长度的内存块。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; */</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; //// </span>根据指定的线性地址和限长（页表个数），释放对应内存页表指定的内存块并置表项空闲。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>页目录位于物理地址<span
lang=EN-US>0</span>开始处，共<span lang=EN-US>1024</span>项，每项<span lang=EN-US>4</span>字节，共占<span
lang=EN-US>4K</span>字节。每个目录项指定一</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>个页表。内核页表从物理地址<span
lang=EN-US>0x1000</span>处开始（紧接着目录空间），共<span lang=EN-US>4</span>个页表。每个页表有</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // 1024</span>项，每项<span
lang=EN-US>4</span>字节。因此也占<span lang=EN-US>4K</span>（<span lang=EN-US>1</span>页）内存。各进程（除了在内核代码中的进程<span
lang=EN-US>0</span>和<span lang=EN-US>1</span>）</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>的页表所占据的页面在进程被创建时由内核为其在主内存区申请得到。每个页表项对应<span
lang=EN-US>1</span>页</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>物理内存，因此一个页表最多可映射<span
lang=EN-US>4MB</span>的物理内存。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>参数：<span lang=EN-US>from
- </span>起始线性基地址；<span lang=EN-US>size - </span>释放的字节长度。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>69</span></u> int
<u><span style='color:blue'>free_page_tables</span></u>(unsigned long
from,unsigned long size)</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>70</span></u> {</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>71</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
unsigned long *pg_table;</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>72</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
unsigned long * dir, nr;</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>73</span></u> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>首先检测参数<span
lang=EN-US>from</span>给出的线性基地址是否在<span lang=EN-US>4MB</span>的边界处。因为该函数只能处理这种情况。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>若<span lang=EN-US>from
= 0</span>，则出错。说明试图释放内核和缓冲所占空间。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>74</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (from &amp; 0x3fffff)</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>75</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>panic</span></u>(<i>&quot;free_page_tables called
with wrong alignment&quot;</i>);</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>76</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (!from)</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>77</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>panic</span></u>(<i>&quot;Trying to free up swapper
memory space&quot;</i>);</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>然后计算参数<span
lang=EN-US>size</span>给出的长度所占的页目录项数（<span lang=EN-US>4MB</span>的进位整数倍），也即所占页表数。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>因为<span lang=EN-US>1</span>个页表可管理<span
lang=EN-US>4MB</span>物理内存，所以这里用右移<span lang=EN-US>22</span>位的方式把需要复制的内存长度值</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>除以<span lang=EN-US>4MB</span>。其中加上<span
lang=EN-US>0x3fffff</span>（即<span lang=EN-US>4Mb -1</span>）用于得到进位整数倍结果，即除操作若有余数</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>则进<span lang=EN-US>1</span>。例如，如果原<span
lang=EN-US>size = 4.01Mb</span>，那么可得到结果<span lang=EN-US>size = 2</span>。 接着计算给出的线性</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>基地址对应的起始目录项。对应的目录项号<span
lang=EN-US> = from &gt;&gt; 22</span>。因为每项占<span lang=EN-US>4</span>字节，并且由于</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>页目录表从物理地址<span
lang=EN-US>0</span>开始存放，因此实际目录项指针<span lang=EN-US> = </span>目录项号<span
lang=EN-US>&lt;&lt;2</span>，也即<span lang=EN-US>(from&gt;&gt;20)</span>。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // “</span>与<span lang=EN-US>”</span>上<span
lang=EN-US>0xffc</span>确保目录项指针范围有效。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>78</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
size = (size + 0x3fffff) &gt;&gt; 22;</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>79</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
dir = (unsigned long *) ((from&gt;&gt;20) &amp; 0xffc); <b><i>/* _pg_dir = 0 */</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>此时<span lang=EN-US>
size </span>是释放的页表个数，即页目录项数，而<span lang=EN-US>dir</span>是起始目录项指针。现在开始循环</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>操作页目录项，依次释放每个页表中的页表项。如果当前目录项无效（<span
lang=EN-US>P</span>位<span lang=EN-US>=0</span>），表示该</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>目录项没有使用（对应的页表不存在），则继续处理下一个目录项。否则从目录项中取出</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>页表地址<span lang=EN-US>
pg_table</span>，并对该页表中的<span lang=EN-US> 1024 </span>个表项进行处理，释放有效页表项（<span
lang=EN-US>P</span>位<span lang=EN-US>=1</span>）</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>对应的物理内存页面，或者从交换设备中释放无效页表项（<span
lang=EN-US>P</span>位<span lang=EN-US>=0</span>）对应的页面，即释放</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>交换设备中对应的内存页面（因为页面可能已经交换出去）。然后把该页表项清零，并继</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>续处理下一页表项。当一个页表所有表项都处理完毕就释放该页表自身占据的内存页面，</p>

<p class=a><span lang=EN-US>&nbsp; &nbsp;&nbsp;// </span>并继续处理下一页目录项。最后刷新页变换高速缓冲，并返回<span
lang=EN-US>0</span>。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>80</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
for ( ; size--&gt;0 ; dir++) {</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>81</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (!(1 &amp; *dir))</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>82</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
continue;</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>83</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
pg_table = (unsigned long *) (0xfffff000 &amp; *dir);&nbsp; // </span>取页表地址。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>84</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
for (nr=0 ; nr&lt;1024 ; nr++) {</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>85</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (*pg_table) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>若所指页表项内容不为<span lang=EN-US>0</span>，则</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>86</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (1 &amp; *pg_table)&nbsp;&nbsp; // </span>若该项有效，则释放对应页。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>87</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>free_page</span></u>(0xfffff000 &amp; *pg_table);</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>88</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
else&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>否则释放交换设备中对应页。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>89</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>swap_free</span></u>(*pg_table &gt;&gt; 1);</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>90</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
*pg_table = 0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // </span>该页表项内容清零。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>91</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>92</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pg_table++;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>指向页表中下一项。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>93</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>94</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>free_page</span></u>(0xfffff000 &amp; *dir);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>释放该页表所占内存页面。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>95</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
*dir = 0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>对应页表的目录项清零。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>96</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>97</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>invalidate</span></u>();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// </span>刷新<span
lang=EN-US>CPU</span>页变换高速缓冲。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>98</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return 0;</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>99</span></u> }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>100</span></u><span
lang=EN-US> </span></p>

<p class=a><u><span lang=EN-US style='color:blue'>101</span></u><span
lang=EN-US> <b><i>/*</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>102</span></u><span
lang=EN-US> <b><i>&nbsp;*&nbsp; Well, here is one of the most complicated
functions in mm. It</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>103</span></u><span
lang=EN-US> <b><i>&nbsp;* copies a range of linerar addresses by copying only
the pages.</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>104</span></u><span
lang=EN-US> <b><i>&nbsp;* Let's hope this is bug-free, 'cause this one I don't
want to debug :-)</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>105</span></u><span
lang=EN-US> <b><i>&nbsp;*</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>106</span></u><span
lang=EN-US> <b><i>&nbsp;* Note! We don't copy just any chunks of memory -
addresses have to</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>107</span></u><span
lang=EN-US> <b><i>&nbsp;* be divisible by 4Mb (one page-directory entry), as
this makes the</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>108</span></u><span
lang=EN-US> <b><i>&nbsp;* function easier. It's used only by fork anyway.</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>109</span></u><span
lang=EN-US> <b><i>&nbsp;*</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>110</span></u><span
lang=EN-US> <b><i>&nbsp;* NOTE 2!! When from==0 we are copying kernel space for
the first</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>111</span></u><span
lang=EN-US> <b><i>&nbsp;* fork(). Then we DONT want to copy a full
page-directory entry, as</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>112</span></u><span
lang=EN-US> <b><i>&nbsp;* that would lead to some serious memory waste - we
just copy the</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>113</span></u><span
lang=EN-US> <b><i>&nbsp;* first 160 pages - 640kB. Even that is more than we
need, but it</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>114</span></u><span
lang=EN-US> <b><i>&nbsp;* doesn't take any more memory - we don't copy-on-write
in the low</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>115</span></u><span
lang=EN-US> <b><i>&nbsp;* 1 Mb-range, so the pages can be shared with the
kernel. Thus the</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>116</span></u><span
lang=EN-US> <b><i>&nbsp;* special case for nr=xxxx.</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>117</span></u><span
lang=EN-US> <b><i>&nbsp;*/</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; /*</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>好了，下面是内存管理<span
lang=EN-US>mm</span>中最为复杂的程序之一。它通过只复制内存页面</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>来拷贝一定范围内线性地址中的内容。
希望代码中没有错误，因为我不想</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>再调试这块代码了<span
lang=EN-US>:-)</span>。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; *</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>注意！我们并不复制任何内存块<span
lang=EN-US> - </span>内存块的地址需要是<span lang=EN-US>4Mb</span>的倍数（正好</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>一个页目录项对应的内存长度），因为这样处理可使函数很简单。
不管怎</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>样，它仅被<span
lang=EN-US>fork()</span>使用。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; *</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>注意<span
lang=EN-US>2</span>！！ 当<span lang=EN-US>from==0</span>时，说明是在为第一次<span
lang=EN-US>fork()</span>调用复制内核空间。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>此时我们就不想复制整个页目录项对应的内存，因为这样做会导致内存严</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>重浪费<span
lang=EN-US> - </span>我们只须复制开头<span lang=EN-US>160</span>个页面<span lang=EN-US> - </span>对应<span
lang=EN-US> 640kB</span>。即使是复制这些</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>页面也已经超出我们的需求，但这不会占用更多的内存<span
lang=EN-US> - </span>在低<span lang=EN-US> 1Mb </span>内存</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>范围内我们不执行写时复制操作，所以这些页面可以与内核共享。因此这</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>是<span
lang=EN-US>nr=xxxx</span>的特殊情况（<span lang=EN-US>nr</span>在程序中指页面数）。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; */</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; //// </span>复制页目录表项和页表项。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>复制指定线性地址和长度内存对应的页目录项和页表项，从而被复制的页目录和页表对应</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>的原物理内存页面区被两套页表映射而共享使用。复制时，需申请新页面来存放新页表，</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>原物理内存区将被共享。此后两个进程（父进程和其子进程）将共享内存区，直到有一个</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>进程执行写操作时，内核才会为写操作进程分配新的内存页（写时复制机制）。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>参数<span lang=EN-US>from</span>、<span
lang=EN-US>to </span>是线性地址，<span lang=EN-US>size</span>是需要复制（共享）的内存长度，单位是字节。</p>

<p class=a><u><span lang=EN-US style='color:blue'>118</span></u><span
lang=EN-US> int <u><span style='color:blue'>copy_page_tables</span></u>(unsigned
long from,unsigned long to,long size)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>119</span></u><span
lang=EN-US> {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>120</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long *
from_page_table;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>121</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long *
to_page_table;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>122</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long
this_page;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>123</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long *
from_dir, * to_dir;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>124</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long
new_page;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>125</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long nr;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>126</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>首先检测参数给出的源地址<span
lang=EN-US>from</span>和目的地址<span lang=EN-US>to</span>的有效性。源地址和目的地址都需要在<span
lang=EN-US>4Mb</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>内存边界地址上。否则出错死机。作这样的要求是因为一个页表的<span
lang=EN-US>1024</span>项可管理<span lang=EN-US>4Mb</span>内存。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>源地址 <span lang=EN-US>from
</span>和目的地址 <span lang=EN-US>to </span>只有满足这个要求才能保证从一个页表的第<span lang=EN-US>1</span>项开始复制页表</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>项，并且新页表的最初所有项都是有效的。<span
lang=EN-US>&nbsp; </span>然后取得源地址和目的地址的起始目录项指针</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>（<span lang=EN-US>from_dir</span>和<span
lang=EN-US>to_dir</span>）。再根据参数给出的长度<span lang=EN-US>size</span>计算要复制的内存块占用的页表数</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>（即目录项数）。参见前面对<span
lang=EN-US>78</span>、<span lang=EN-US>79</span>行的解释。</p>

<p class=a><u><span lang=EN-US style='color:blue'>127</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if
((from&amp;0x3fffff) || (to&amp;0x3fffff))</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>128</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>panic</span></u>(<i>&quot;copy_page_tables called
with wrong alignment&quot;</i>);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>129</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from_dir =
(unsigned long *) ((from&gt;&gt;20) &amp; 0xffc); <b><i>/* _pg_dir = 0 */</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>130</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; to_dir = (unsigned
long *) ((to&gt;&gt;20) &amp; 0xffc);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>131</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; size = ((unsigned)
(size+0x3fffff)) &gt;&gt; 22;</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>在得到了源起始目录项指针<span
lang=EN-US>from_dir</span>和目的起始目录项指针<span lang=EN-US>to_dir</span>以及需要复制的页表</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>个数<span lang=EN-US>
size </span>后，下面开始对每个页目录项依次申请<span lang=EN-US>1</span>页内存来保存对应的页表，并且开始</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>页表项复制操作。如果目的目录项指定的页表已经存在（<span
lang=EN-US>P=1</span>），则出错死机。 如果源目</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>录项无效，即指定的页表不存在（<span
lang=EN-US>P=0</span>），则继续循环处理下一个页目录项。</p>

<p class=a><u><span lang=EN-US style='color:blue'>132</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for( ; size--&gt;0
; from_dir++,to_dir++) {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>133</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (1 &amp; *to_dir)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>134</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>panic</span></u>(<i>&quot;copy_page_tables: already
exist&quot;</i>);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>135</span></u><span
lang=EN-US> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if
(!(1 &amp; *from_dir))</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>136</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
continue;</span></p>

<p class=a><span lang=EN-US>&nbsp;</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>在验证了当前源目录项和目的项正常之后，我们取源目录项中页表地址<span
lang=EN-US>from_page_table</span>。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>为了保存目的目录项对应的页表，需要在主内存区中申请<span
lang=EN-US>1</span>页空闲内存页。如果取空闲页面</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>函数<span lang=EN-US>get_free_page()
</span>返回<span lang=EN-US>0</span>，则说明没有申请到空闲内存页面，可能是内存不够。于是返</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>回<span lang=EN-US>-1</span>值退出。</p>

<p class=a><u><span lang=EN-US style='color:blue'>137</span></u><span
lang=EN-US>&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from_page_table
= (unsigned long *) (0xfffff000 &amp; *from_dir);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>138</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (!(to_page_table = (unsigned long *) <u><span style='color:blue'>get_free_page</span></u>()))</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>139</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return -1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <b><i>/* Out of memory, see freeing */</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>否则我们设置目的目录项信息，把最后<span
lang=EN-US>3</span>位置位，即当前目的目录项“或”上<span lang=EN-US>7</span>，表示对应</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>页表映射的内存页面是用户级的，并且可读写、存在（<span
lang=EN-US>Usr, R/W, Present</span>）。 （如果<span lang=EN-US>U/S</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>位是<span lang=EN-US>0</span>，则<span
lang=EN-US>R/W</span>就没有作用。如果 <span lang=EN-US>U/S</span>是<span lang=EN-US>1</span>，而<span
lang=EN-US> R/W</span>是<span lang=EN-US>0</span>，那么运行在用户层的代码就只能</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>读页面。如果<span
lang=EN-US>U/S</span>和<span lang=EN-US>R/W</span>都置位，则就有读写的权限）。然后针对当前处理的页目录项对应</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>的页表，设置需要复制的页面项数。如果是在内核空间，则仅需复制头<span
lang=EN-US>160</span>页对应的页表项</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>（<span lang=EN-US>nr=
160</span>），对应于开始<span lang=EN-US>640KB</span>物理内存。否则需要复制一个页表中的所有<span
lang=EN-US>1024</span>个页表项</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>（<span lang=EN-US>nr=
1024</span>），可映射<span lang=EN-US>4MB</span>物理内存。</p>

<p class=a><u><span lang=EN-US style='color:blue'>140</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
*to_dir = ((unsigned long) to_page_table) | 7;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>141</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
nr = (from==0)?0xA0:1024;</span></p>

<p class=a><span lang=EN-US>&nbsp;</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>此时对于当前页表，开始循环复制指定的<span
lang=EN-US>nr</span>个内存页面表项。先取出源页表项内容，如果</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>当前源页面没有使用（项内容为<span
lang=EN-US>0</span>），则不用复制该表项，继续处理下一项。</p>

<p class=a><u><span lang=EN-US style='color:blue'>142</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
for ( ; nr-- &gt; 0 ; from_page_table++,to_page_table++) {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>143</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
this_page = *from_page_table;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>144</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (!this_page)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>145</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
continue;</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>如果该表项有内容，但是其存在位<span
lang=EN-US>P=0</span>，则该表项对应的页面可能在交换设备中。于是先申</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>请<span lang=EN-US>1</span>页内存，并从交换设备中读入该页面（若交换设备中有的话）。然后将该页表项复制到</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>目的页表项中。并修改源页表项内容指向该新申请的内存页，并设置表项标志为“页面脏”</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>加上<span lang=EN-US>7</span>。然后继续处理下一页表项。否则复位页表项中
<span lang=EN-US>R/W </span>标志（位<span lang=EN-US>1</span>置<span lang=EN-US>0</span>），即让页表项</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>对应的内存页面只读，然后将该页表项复制到目的页表中。</p>

<p class=a><u><span lang=EN-US style='color:blue'>146</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;if (!(1 &amp; this_page)) {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>147</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (!(new_page = <u><span style='color:blue'>get_free_page</span></u>()))</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>148</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return -1;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>149</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>read_swap_page</span></u>(this_page&gt;&gt;1, (char
*) new_page);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>150</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*to_page_table
= this_page;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>151</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
*from_page_table = new_page | (<u><span style='color:blue'>PAGE_DIRTY</span></u>
| 7);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>152</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
continue;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>153</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>154</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
this_page &amp;= ~2;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>155</span></u><span
lang=EN-US>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*to_page_table
= this_page;</span></p>

<p class=a><span lang=EN-US>&nbsp;</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>如果该页表项所指物理页面的地址在<span
lang=EN-US>1MB</span>以上，则需要设置内存页面映射数组<span lang=EN-US>mem_map[]</span>，</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>于是计算页面号，并以它为索引在页面映射数组相应项中增加引用次数。而对于位于<span
lang=EN-US>1MB</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>以下的页面，说明是内核页面，因此不需要对<span
lang=EN-US>mem_map[]</span>进行设置。因为 <span lang=EN-US>mem_map[]</span>仅用</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>于管理主内存区中的页面使用情况。 因此对于内核移动到任务<span
lang=EN-US>0</span>中并且调用<span lang=EN-US>fork()</span>创建</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>任务<span lang=EN-US>1</span>时（用于运行<span
lang=EN-US>init()</span>），由于此时复制的页面还仍然都在内核代码区域，因此以下</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>判断中的语句不会执行，任务<span
lang=EN-US>0 </span>的页面仍然可以随时读写。只有当调用 <span lang=EN-US>fork() </span>的父进程</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>代码处于主内存区（页面位置大于<span
lang=EN-US>1MB</span>）时才会执行。这种情况需要在进程调用<span lang=EN-US>execve()</span>，</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>并装载执行了新程序代码时才会出现。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // 157</span>行语句含义是令源页表项所指内存页也为只读。因为现在开始已有两个进程共用内存</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>区了。若其中<span
lang=EN-US>1</span>个进程需要进行写操作，则可以通过页异常写保护处理为执行写操作的进</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>程分配<span lang=EN-US>1</span>页新空闲页面，也即进行写时复制（<span
lang=EN-US>copy on write</span>）操作。</p>

<p class=a><u><span lang=EN-US style='color:blue'>156</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (this_page &gt; <u><span style='color:blue'>LOW_MEM</span></u>) {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>157</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
*from_page_table = this_page; // </span>令源页表项也只读。</p>

<p class=a><u><span lang=EN-US style='color:blue'>158</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this_page -= <u><span style='color:blue'>LOW_MEM</span></u>;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>159</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
this_page &gt;&gt;= 12;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>160</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>mem_map</span></u>[this_page]++;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>161</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>162</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>163</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>164</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>invalidate</span></u>();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// </span>刷新页变换高速缓冲。</p>

<p class=a><u><span lang=EN-US style='color:blue'>165</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>166</span></u><span
lang=EN-US> }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>167</span></u><span
lang=EN-US> </span></p>

<p class=a><u><span lang=EN-US style='color:blue'>168</span></u><span
lang=EN-US> <b><i>/*</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>169</span></u><span
lang=EN-US> <b><i>&nbsp;* This function puts a page in memory at the wanted
address.</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>170</span></u><span
lang=EN-US> <b><i>&nbsp;* It returns the physical address of the page gotten, 0
if</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>171</span></u><span
lang=EN-US> <b><i>&nbsp;* out of memory (either when trying to access
page-table or</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>172</span></u><span
lang=EN-US> <b><i>&nbsp;* page.)</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>173</span></u><span
lang=EN-US> <b><i>&nbsp;*/</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; /*</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>下面函数将一内存页面放置（映射）到指定线性地址处。它返回页面</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>的物理地址，如果内存不够<span
lang=EN-US>(</span>在访问页表或页面时<span lang=EN-US>)</span>，则返回<span lang=EN-US>0</span>。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; */</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>把一物理内存页面映射到线性地址空间指定处。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>或者说是把线性地址空间中指定地址<span
lang=EN-US>address</span>处的页面映射到主内存区页面<span lang=EN-US>page</span>上。主要</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>工作是在相关页目录项和页表项中设置指定页面的信息。若成功则返回物理页面地址。
在</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>处理缺页异常的<span
lang=EN-US>C</span>函数<span lang=EN-US>do_no_page() </span>中会调用此函数。对于缺页引起的异常，由于任何缺</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>页缘故而对页表作修改时，并不需要刷新<span
lang=EN-US>CPU</span>的页变换缓冲（或称<span lang=EN-US>Translation Lookaside</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // Buffer - TLB</span>），即使页表项中标志<span
lang=EN-US>P</span>被从<span lang=EN-US>0</span>修改成<span lang=EN-US>1</span>。因为无效页项不会被缓冲，因此当</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>修改了一个无效的页表项时不需要刷新。在此就表现为不用调用<span
lang=EN-US>Invalidate()</span>函数。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>参数<span lang=EN-US>page</span>是分配的主内存区中某一页面（页帧，页框）的指针；<span
lang=EN-US>address</span>是线性地址。</p>

<p class=a><u><span lang=EN-US style='color:blue'>174</span></u><span
lang=EN-US> static unsigned long <u><span style='color:blue'>put_page</span></u>(unsigned
long page,unsigned long address)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>175</span></u><span
lang=EN-US> {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>176</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long tmp,
*page_table;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>177</span></u><span
lang=EN-US> </span></p>

<p class=a><u><span lang=EN-US style='color:blue'>178</span></u><span
lang=EN-US> <b><i>/* NOTE !!! This uses the fact that _pg_dir=0 */</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; /* </span>注意<span lang=EN-US>!!!
</span>这里使用了页目录表基地址<span lang=EN-US>_pg_dir=0</span>的条件<span lang=EN-US> */</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>179</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>首先判断参数给定物理内存页面<span
lang=EN-US>page </span>的有效性。如果该页面位置低于<span lang=EN-US>LOW_MEM</span>（<span
lang=EN-US>1MB</span>）或</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>超出系统实际含有内存高端 <span
lang=EN-US>HIGH_MEMORY</span>，则发出警告。<span lang=EN-US>LOW_MEM </span>是主内存区可能有的最</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>小起始位置。当系统物理内存小于或等于<span
lang=EN-US>6MB</span>时，主内存区起始于<span lang=EN-US>LOW_MEM</span>处。再查看一</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>下该<span lang=EN-US>
page</span>页面是否是已经申请的页面，即判断其在内存页面映射字节图<span lang=EN-US> mem_map[]</span>中相</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>应字节是否已经置位。若没有则需发出警告。</p>

<p class=a><u><span lang=EN-US style='color:blue'>180</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (page &lt; <u><span
style='color:blue'>LOW_MEM</span></u> || page &gt;= <u><span style='color:blue'>HIGH_MEMORY</span></u>)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>181</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>printk</span></u>(<i>&quot;Trying to put page %p at
%p\n&quot;</i>,page,address);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>182</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (<u><span
style='color:blue'>mem_map</span></u>[(page-<u><span style='color:blue'>LOW_MEM</span></u>)&gt;&gt;12]
!= 1)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>183</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>printk</span></u>(<i>&quot;mem_map disagrees with
%p at %p\n&quot;</i>,page,address);</span></p>

<p class=a><span lang=EN-US>&nbsp;</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>然后根据参数指定的线性地址<span
lang=EN-US>address</span>计算其在页目录表中对应的目录项指针，并从中取得</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>二级页表地址。 如果该目录项有效（<span
lang=EN-US>P=1</span>），即指定的页表在内存中，则从中取得指定页表</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>地址放到<span lang=EN-US>page_table
</span>变量中。否则申请一空闲页面给页表使用，并在对应目录项中置相应</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>标志（<span lang=EN-US>7 –
User</span>、<span lang=EN-US>U/S</span>、<span lang=EN-US>R/W</span>）。然后将该页表地址放到<span
lang=EN-US>page_table</span>变量中。</p>

<p class=a><u><span lang=EN-US style='color:blue'>184</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; page_table =
(unsigned long *) ((address&gt;&gt;20) &amp; 0xffc);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>185</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if
((*page_table)&amp;1)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>186</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
page_table = (unsigned long *) (0xfffff000 &amp; *page_table);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>187</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>188</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (!(tmp=<u><span style='color:blue'>get_free_page</span></u>()))</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>189</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return 0;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>190</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
*page_table = tmp | 7;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>191</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
page_table = (unsigned long *) tmp;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>192</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>最后在找到的页表<span
lang=EN-US> page_table </span>中设置相关页表项内容，即把物理页面<span lang=EN-US>page</span>的地址填入表</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>项同时置位<span lang=EN-US>3</span>个标志（<span
lang=EN-US>U/S</span>、<span lang=EN-US>W/R</span>、<span lang=EN-US>P</span>）。该页表项在页表中的索引值等于线性地址位<span
lang=EN-US>21 --</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>位<span lang=EN-US>12</span>组成的<span
lang=EN-US>10</span>比特的值。每个页表共可有<span lang=EN-US>1024</span>项（<span lang=EN-US>0
-- 0x3ff</span>）。</p>

<p class=a><u><span lang=EN-US style='color:blue'>193</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
page_table[(address&gt;&gt;12) &amp; 0x3ff] = page | 7;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>194</span></u><span
lang=EN-US> <b><i>/* no need for invalidate */</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; /* </span>不需要刷新页变换高速缓冲<span
lang=EN-US> */</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>195</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return page;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>返回物理页面地址。</p>

<p class=a><u><span lang=EN-US style='color:blue'>196</span></u><span
lang=EN-US> }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>197</span></u><span
lang=EN-US> </span></p>

<p class=a><u><span lang=EN-US style='color:blue'>198</span></u><span
lang=EN-US> <b><i>/*</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>199</span></u><span
lang=EN-US> <b><i>&nbsp;* The previous function doesn't work very well if you also
want to mark</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>200</span></u><span
lang=EN-US> <b><i>&nbsp;* the page dirty: exec.c wants this, as it has earlier
changed the page,</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>201</span></u><span
lang=EN-US> <b><i>&nbsp;* and we want the dirty-status to be correct (for VM).
Thus the same</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>202</span></u><span
lang=EN-US> <b><i>&nbsp;* routine, but this time we mark it dirty too.</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>203</span></u><span
lang=EN-US> <b><i>&nbsp;*/</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; /*</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>如果你也想设置页面已修改标志，则上一个函数工作得不是很好：<span
lang=EN-US>exec.c</span>程序</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>需要这种设置。因为<span
lang=EN-US>exec.c</span>中函数会在放置页面之前修改过页面内容。为了实</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>现<span
lang=EN-US>VM</span>，我们需要能正确设置已修改状态标志。因而下面就有了与上面相同的函</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>数，但是该函数在放置页面时会把页面标志为已修改状态。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; */</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>把一内容已修改过的物理内存页面映射到线性地址空间指定处。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>该函数与上一个函数<span
lang=EN-US>put_page()</span>几乎完全一样，除了本函数在<span lang=EN-US>223</span>行设置页表项内容时，</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>同时还设置了页面已修改标志（位<span
lang=EN-US>6</span>，<span lang=EN-US>PAGE_DIRTY</span>）。</p>

<p class=a><u><span lang=EN-US style='color:blue'>204</span></u><span
lang=EN-US> unsigned long <u><span style='color:blue'>put_dirty_page</span></u>(unsigned
long page, unsigned long address)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>205</span></u><span
lang=EN-US> {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>206</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long tmp,
*page_table;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>207</span></u><span
lang=EN-US> </span></p>

<p class=a><u><span lang=EN-US style='color:blue'>208</span></u><span
lang=EN-US> <b><i>/* NOTE !!! This uses the fact that _pg_dir=0 */</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>209</span></u><span
lang=EN-US> </span></p>

<p class=a><u><span lang=EN-US style='color:blue'>210</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (page &lt; <u><span
style='color:blue'>LOW_MEM</span></u> || page &gt;= <u><span style='color:blue'>HIGH_MEMORY</span></u>)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>211</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>printk</span></u>(<i>&quot;Trying to put page %p at
%p\n&quot;</i>,page,address);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>212</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (<u><span
style='color:blue'>mem_map</span></u>[(page-<u><span style='color:blue'>LOW_MEM</span></u>)&gt;&gt;12]
!= 1)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>213</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>printk</span></u>(<i>&quot;mem_map disagrees with
%p at %p\n&quot;</i>,page,address);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>214</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; page_table = (unsigned
long *) ((address&gt;&gt;20) &amp; 0xffc);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>215</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if
((*page_table)&amp;1)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>216</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
page_table = (unsigned long *) (0xfffff000 &amp; *page_table);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>217</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>218</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (!(tmp=<u><span style='color:blue'>get_free_page</span></u>()))</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>219</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return 0;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>220</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
*page_table = tmp|7;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>221</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
page_table = (unsigned long *) tmp;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>222</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>223</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
page_table[(address&gt;&gt;12) &amp; 0x3ff] = page | (<u><span
style='color:blue'>PAGE_DIRTY</span></u> | 7);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>224</span></u><span
lang=EN-US> <b><i>/* no need for invalidate */</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>225</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return page;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>226</span></u><span
lang=EN-US> }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>227</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; //// </span>取消写保护页面函数。用于页异常中断过程中写保护异常的处理（写时复制）。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>在内核创建进程时，新进程与父进程被设置成共享代码和数据内存页面，并且所有这些页面</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>均被设置成只读页面。而当新进程或原进程需要向内存页面写数据时，<span
lang=EN-US>CPU </span>就会检测到这个</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>情况并产生页面写保护异常。于是在这个函数中内核就会首先判断要写的页面是否被共享。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>若没有则把页面设置成可写然后退出。若页面是出于共享状态，则需要重新申请一新页面并</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>复制被写页面内容，以供写进程单独使用。共享被取消。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>输入参数为页表项指针，是物理地址。<span
lang=EN-US>[ un_wp_page -- Un-Write Protect Page]</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>228</span></u><span
lang=EN-US> void <u><span style='color:blue'>un_wp_page</span></u>(unsigned
long * table_entry)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>229</span></u><span
lang=EN-US> {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>230</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long
old_page,new_page;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>231</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>首先取参数指定的页表项中物理页面位置（地址）并判断该页面是否是共享页面。如果原</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>页面地址大于内存低端<span
lang=EN-US> LOW_MEM</span>（表示在主内存区中），并且其在页面映射字节图数组中</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>值为<span lang=EN-US>1</span>（表示页面仅被引用<span
lang=EN-US>1</span>次，页面没有被共享），则在该页面的页表项中置<span lang=EN-US> R/W </span>标志</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>（可写），并刷新页变换高速缓冲，然后返回。即如果该内存页面此时只被一个进程使用，</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>并且不是内核中的进程，就直接把属性改为可写即可，不用再重新申请一个新页面。</p>

<p class=a><u><span lang=EN-US style='color:blue'>232</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; old_page =
0xfffff000 &amp; *table_entry;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // </span>取指定页表项中物理页面地址。</p>

<p class=a><u><span lang=EN-US style='color:blue'>233</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (old_page &gt;= <u><span
style='color:blue'>LOW_MEM</span></u> &amp;&amp; <u><span style='color:blue'>mem_map</span></u>[<u><span
style='color:blue'>MAP_NR</span></u>(old_page)]==1) {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>234</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
*table_entry |= 2;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>235</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>invalidate</span></u>();</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>236</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>237</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>否则就需要在主内存区内申请一页空闲页面给执行写操作的进程单独使用，取消页面共享。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>如果原页面大于内存低端（则意味着 <span
lang=EN-US>mem_map[] &gt; 1</span>，页面是共享的），则将原页面的页</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>面映射字节数组值递减<span
lang=EN-US>1</span>。然后将指定页表项内容更新为新页面地址，并置可读写等标志</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>（<span lang=EN-US>U/S</span>、<span
lang=EN-US>R/W</span>、<span lang=EN-US>P</span>）。在刷新页变换高速缓冲之后，最后将原页面内容复制到新页面。</p>

<p class=a><u><span lang=EN-US style='color:blue'>238</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!(new_page=<u><span
style='color:blue'>get_free_page</span></u>()))</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>239</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>oom</span></u>();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// Out of Memory</span>。内存不够处理。</p>

<p class=a><u><span lang=EN-US style='color:blue'>240</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (old_page &gt;= <u><span
style='color:blue'>LOW_MEM</span></u>)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>241</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>mem_map</span></u>[<u><span style='color:blue'>MAP_NR</span></u>(old_page)]--;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>242</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>copy_page</span></u>(old_page,new_page);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>243</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *table_entry =
new_page | 7;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>244</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>invalidate</span></u>();</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>245</span></u><span
lang=EN-US> }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></p>

<p class=a><u><span lang=EN-US style='color:blue'>246</span></u><span
lang=EN-US> </span></p>

<p class=a><u><span lang=EN-US style='color:blue'>247</span></u><span
lang=EN-US> <b><i>/*</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>248</span></u><span
lang=EN-US> <b><i>&nbsp;* This routine handles present pages, when users try to
write</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>249</span></u><span
lang=EN-US> <b><i>&nbsp;* to a shared page. It is done by copying the page to a
new address</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>250</span></u><span
lang=EN-US> <b><i>&nbsp;* and decrementing the shared-page counter for the old
page.</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>251</span></u><span
lang=EN-US> <b><i>&nbsp;*</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>252</span></u><span
lang=EN-US> <b><i>&nbsp;* If it's in code space we exit with a segment error.</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>253</span></u><span
lang=EN-US> <b><i>&nbsp;*/</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; /*</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>当用户试图往一共享页面上写时，该函数处理已存在的内存页面（写时复制），</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>它是通过将页面复制到一个新地址上并且递减原页面的共享计数值实现的。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; *</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>如果它在代码空间，我们就显示段出错信息并退出。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; */</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; //// </span>执行写保护页面处理。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>是写共享页面处理函数。是页异常中断处理过程中调用的<span
lang=EN-US>C</span>函数。在<span lang=EN-US>page.s</span>程序中被调用。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>函数参数<span lang=EN-US>error_code
</span>和 <span lang=EN-US>address </span>是进程在写写保护页面时由<span lang=EN-US> CPU</span>产生异常而自动生成的。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // error_code</span>指出出错类型，参见本章开始处的“内存页面出错异常”一节；<span
lang=EN-US>address</span>是产生</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>异常的页面线性地址。写共享页面时需复制页面（写时复制）。</p>

<p class=a><u><span lang=EN-US style='color:blue'>254</span></u><span
lang=EN-US> void <u><span style='color:blue'>do_wp_page</span></u>(unsigned
long error_code,unsigned long address)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>255</span></u><span
lang=EN-US> {</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>首先判断<span lang=EN-US>CPU</span>控制寄存器<span
lang=EN-US>CR2</span>给出的引起页面异常的线性地址在什么范围中。如果<span lang=EN-US>address</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>小于<span lang=EN-US>
TASK_SIZE</span>（<span lang=EN-US>0x4000000</span>，即<span lang=EN-US>64MB</span>），表示异常页面位置在内核或任务<span
lang=EN-US>0</span>和任务<span lang=EN-US>1</span>所处</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>的线性地址范围内，于是发出警告信息“内核范围内存被写保护”；如果<span
lang=EN-US> (address–</span>当前</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>进程代码起始地址<span
lang=EN-US>)</span>大于一个进程的长度（<span lang=EN-US>64MB</span>），表示<span lang=EN-US>address</span>所指的线性地址不在引起</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>异常的进程线性地址空间范围内，则在发出出错信息后退出。</p>

<p class=a><u><span lang=EN-US style='color:blue'>256</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (address &lt; <u><span
style='color:blue'>TASK_SIZE</span></u>)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>257</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>printk</span></u>(<i>&quot;\n\rBAD! KERNEL MEMORY
WP-ERR!\n\r&quot;</i>);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>258</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (address - <u><span
style='color:blue'>current</span></u>-&gt;start_code &gt; <u><span
style='color:blue'>TASK_SIZE</span></u>) {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>259</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>printk</span></u>(<i>&quot;Bad things happen: page
error in do_wp_page\n\r&quot;</i>);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>260</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>do_exit</span></u>(<u><span style='color:blue'>SIGSEGV</span></u>);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>261</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>262</span></u><span
lang=EN-US> #if 0</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>263</span></u><span
lang=EN-US> <b><i>/* we cannot do this yet: the estdio library writes to code
space */</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>264</span></u><span
lang=EN-US> <b><i>/* stupid, stupid. I really want the libc.a from GNU */</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; /* </span>我们现在还不能这样做：因为<span
lang=EN-US>estdio</span>库会在代码空间执行写操作<span lang=EN-US> */</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; /* </span>真是太愚蠢了。我真想从<span
lang=EN-US>GNU</span>得到<span lang=EN-US>libc.a</span>库。<span lang=EN-US>*/</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>如果线性地址位于进程的代码空间中，则终止执行程序。因为代码是只读的。</p>

<p class=a><u><span lang=EN-US style='color:blue'>265</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (<u><span
style='color:blue'>CODE_SPACE</span></u>(address))</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>266</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>do_exit</span></u>(<u><span style='color:blue'>SIGSEGV</span></u>);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>267</span></u><span
lang=EN-US> #endif</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>调用上面函数<span
lang=EN-US>un_wp_page()</span>来处理取消页面保护。但首先需要为其准备好参数。参数是</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>线性地址<span lang=EN-US>address</span>指定页面在页表中的页表项指针，其计算方法是：</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>①<span lang=EN-US>
((address&gt;&gt;10) &amp; 0xffc)</span>：计算指定线性地址中页表项在页表中的偏移地址；因为</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>根据线性地址结构，<span
lang=EN-US>(address&gt;&gt;12) </span>就是页表项中的索引，但每项占<span lang=EN-US>4</span>个字节，因此乘</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // 4</span>后：<span lang=EN-US>(address&gt;&gt;12)&lt;&lt;2
= (address&gt;&gt;10)&amp;0xffc </span>就可得到页表项在表中的偏移地址。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>与操作<span lang=EN-US>&amp;0xffc</span>用于限制地址范围在一个页面内。
又因为只移动了<span lang=EN-US>10</span>位，因此最后<span lang=EN-US>2</span>位</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>是线性地址低<span
lang=EN-US>12 </span>位中的最高<span lang=EN-US>2</span>位，也应屏蔽掉。 因此求线性地址中页表项在页表中偏</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>移地址直观一些的表示方法是<span
lang=EN-US>(((address&gt;&gt;12) &amp; 0x3ff)&lt;&lt;2 )</span>。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>②<span lang=EN-US>
(0xfffff000 &amp; *((address&gt;&gt;20) &amp;0xffc))</span>：用于取目录项中页表的地址值；其中，</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // ((address&gt;&gt;20)
&amp;0xffc)</span>用于取线性地址中的目录索引项在目录表中的偏移位置。因为</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // address&gt;&gt;22 </span>是目录项索引值，但每项<span
lang=EN-US>4</span>个字节，因此乘以<span lang=EN-US>4</span>后： <span lang=EN-US>(address&gt;&gt;22)&lt;&lt;2
</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // = (address&gt;&gt;20) </span>就是指定项在目录表中的偏移地址。
<span lang=EN-US>&amp;0xffc</span>用于屏蔽目录项索引值</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>中最后<span lang=EN-US>2</span>位。因为只移动了<span
lang=EN-US>20</span>位，因此最后<span lang=EN-US>2</span>位是页表索引的内容，应该屏蔽掉。而</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // *((address&gt;&gt;20)
&amp;0xffc) </span>则是取指定目录表项内容中对应页表的物理地址。最后与上</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // 0xffffff000</span>用于屏蔽掉页目录项内容中的一些标志位（目录项低<span
lang=EN-US>12</span>位）。直观表示为</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // (0xffffff000 &amp;
*((unsigned long *) (((address&gt;&gt;22) &amp; 0x3ff)&lt;&lt;2)))</span>。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>③ 由①中页表项在页表中偏移地址加上 ②中目录表项内容中对应页表的物理地址即可</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>得到页表项的指针（物理地址）。这里对共享的页面进行复制。</p>

<p class=a><u><span lang=EN-US style='color:blue'>268</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>un_wp_page</span></u>((unsigned long *)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>269</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
(((address&gt;&gt;10) &amp; 0xffc) + (0xfffff000 &amp;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>270</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
*((unsigned long *) ((address&gt;&gt;20) &amp;0xffc)))));</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>271</span></u><span
lang=EN-US> </span></p>

<p class=a><u><span lang=EN-US style='color:blue'>272</span></u><span
lang=EN-US> }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>273</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; //// </span>写页面验证。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>若页面不可写，则复制页面。在<span
lang=EN-US>fork.c</span>中第<span lang=EN-US>34</span>行被内存验证通用函数<span lang=EN-US>verify_area()</span>调用。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>参数<span lang=EN-US>address</span>是指定页面在<span
lang=EN-US>4G</span>空间中的线性地址。</p>

<p class=a><u><span lang=EN-US style='color:blue'>274</span></u><span
lang=EN-US> void <u><span style='color:blue'>write_verify</span></u>(unsigned
long address)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>275</span></u><span
lang=EN-US> {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>276</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long page;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>277</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>首先取指定线性地址对应的页目录项，根据目录项中的存在位（<span
lang=EN-US>P</span>）判断目录项对应的页表</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>是否存在（存在位<span
lang=EN-US>P=1?</span>），若不存在（<span lang=EN-US>P=0</span>）则返回。这样处理是因为对于不存在的页面没</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>有共享和写时复制可言，并且若程序对此不存在的页面执行写操作时，系统就会因为缺页异</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>常而去执行<span lang=EN-US>do_no_page()</span>，并为这个地方使用
<span lang=EN-US>put_page()</span>函数映射一个物理页面。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>接着程序从目录项中取页表地址，加上指定页面在页表中的页表项偏移值，得对应地址的页</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>表项指针。在该表项中包含着给定线性地址对应的物理页面。</p>

<p class=a><u><span lang=EN-US style='color:blue'>278</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!( (page =
*((unsigned long *) ((address&gt;&gt;20) &amp; 0xffc)) )&amp;1))</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>279</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>280</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; page &amp;=
0xfffff000;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>281</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; page +=
((address&gt;&gt;10) &amp; 0xffc);</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>然后判断该页表项中的位<span
lang=EN-US>1</span>（<span lang=EN-US>R/W</span>）、位<span lang=EN-US>0</span>（<span
lang=EN-US>P</span>）标志。如果该页面不可写（<span lang=EN-US>R/W=0</span>）且存在，</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>那么就执行共享检验和复制页面操作（写时复制）。否则什么也不做，直接退出。</p>

<p class=a><u><span lang=EN-US style='color:blue'>282</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ((3 &amp;
*(unsigned long *) page) == 1)&nbsp; <b><i>/* non-writeable, present */</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>283</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>un_wp_page</span></u>((unsigned long *) page);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>284</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>285</span></u><span
lang=EN-US> }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>286</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; //// </span>取得一页空闲内存页并映射到指定线性地址处。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // get_free_page()</span>仅是申请取得了主内存区的一页物理内存。而本函数则不仅是获取到一页</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>物理内存页面，还进一步调用<span
lang=EN-US>put_page()</span>，将物理页面映射到指定的线性地址处。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>参数<span lang=EN-US>address</span>是指定页面的线性地址。</p>

<p class=a><u><span lang=EN-US style='color:blue'>287</span></u><span
lang=EN-US> void <u><span style='color:blue'>get_empty_page</span></u>(unsigned
long address)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>288</span></u><span
lang=EN-US> {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>289</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long tmp;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>290</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>若不能取得一空闲页面，或者不能将所取页面放置到指定地址处，则显示内存不够的信息。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // 292</span>行上英文注释的含义是：<span
lang=EN-US>free_page()</span>函数的参数<span lang=EN-US>tmp</span>是<span lang=EN-US>0</span>也没有关系，该函数会忽略</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>它并能正常返回。</p>

<p class=a><u><span lang=EN-US style='color:blue'>291</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!(tmp=<u><span
style='color:blue'>get_free_page</span></u>()) || !<u><span style='color:blue'>put_page</span></u>(tmp,address))
{</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>292</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>free_page</span></u>(tmp);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<b><i>/* 0 is ok - ignored */</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>293</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>oom</span></u>();</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>294</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>295</span></u><span
lang=EN-US> }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>296</span></u><span
lang=EN-US> </span></p>

<p class=a><u><span lang=EN-US style='color:blue'>297</span></u><span
lang=EN-US> <b><i>/*</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>298</span></u><span
lang=EN-US> <b><i>&nbsp;* try_to_share() checks the page at address
&quot;address&quot; in the task &quot;p&quot;,</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>299</span></u><span
lang=EN-US> <b><i>&nbsp;* to see if it exists, and if it is clean. If so, share
it with the current</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>300</span></u><span
lang=EN-US> <b><i>&nbsp;* task.</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>301</span></u><span
lang=EN-US> <b><i>&nbsp;*</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>302</span></u><span
lang=EN-US> <b><i>&nbsp;* NOTE! This assumes we have checked that p != current,
and that they</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>303</span></u><span
lang=EN-US> <b><i>&nbsp;* share the same executable or library.</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>304</span></u><span
lang=EN-US> <b><i>&nbsp;*/</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; /*</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * try_to_share()</span>在任务<span
lang=EN-US>&quot;p&quot;</span>中检查位于地址<span lang=EN-US>&quot;address&quot;</span>处的页面，看页面是否存在，</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>是否干净。如果是干净的话，就与当前任务共享。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; *</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>注意！这里我们已假定<span
lang=EN-US>p !=</span>当前任务，并且它们共享同一个执行程序或库程序。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; */</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; //// </span>尝试对当前进程指定地址处的页面进行共享处理。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>当前进程与进程<span
lang=EN-US>p</span>是同一执行代码，也可以认为当前进程是由<span lang=EN-US>p</span>进程执行<span
lang=EN-US>fork</span>操作产生的</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>进程，因此它们的代码内容一样。如果未对数据段内容作过修改那么数据段内容也应一样。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>参数 <span lang=EN-US>address
</span>是进程中的逻辑地址，即是当前进程欲与 <span lang=EN-US>p </span>进程共享页面的逻辑页面地址。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>进程<span lang=EN-US>p</span>是将被共享页面的进程。如果<span
lang=EN-US>p</span>进程<span lang=EN-US>address</span>处的页面存在并且没有被修改过的话，</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>就让当前进程与<span
lang=EN-US>p</span>进程共享之。同时还需要验证指定的地址处是否已经申请了页面，若是</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>则出错，死机。返回：<span
lang=EN-US>1 - </span>页面共享处理成功；<span lang=EN-US>0 - </span>失败。</p>

<p class=a><u><span lang=EN-US style='color:blue'>305</span></u><span
lang=EN-US> static int <u><span style='color:blue'>try_to_share</span></u>(unsigned
long address, struct <u><span style='color:blue'>task_struct</span></u> * p)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>306</span></u><span
lang=EN-US> {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>307</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long from;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>308</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long to;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>309</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long
from_page;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>310</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long
to_page;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>311</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long
phys_addr;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>312</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>首先分别求得指定进程<span
lang=EN-US>p</span>中和当前进程中逻辑地址<span lang=EN-US>address</span>对应的页目录项。为了计算方便</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>先求出指定逻辑地址<span
lang=EN-US>address</span>处的<span lang=EN-US>'</span>逻辑<span lang=EN-US>'</span>页目录项号，即以进程空间（<span
lang=EN-US>0 - 64MB</span>）算出的页</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>目录项号。该<span
lang=EN-US>'</span>逻辑<span lang=EN-US>'</span>页目录项号加上进程<span lang=EN-US>p </span>在<span
lang=EN-US>CPU 4G</span>线性空间中起始地址对应的页目录项，</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>即得到进程<span lang=EN-US>p</span>中地址
<span lang=EN-US>address </span>处页面所对应的<span lang=EN-US>4G </span>线性空间中的实际页目录项<span
lang=EN-US>from_page</span>。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>而<span lang=EN-US>'</span>逻辑<span
lang=EN-US>'</span>页目录项号加上当前进程<span lang=EN-US>CPU 4G </span>线性空间中起始地址对应的页目录项，即可最后</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>得到当前进程中地址<span
lang=EN-US>address</span>处页面所对应的<span
 lang=EN-US>4G</span>线性空间中的实际页目录项<span lang=EN-US>to_page</span>。</p>

<p class=a><u><span lang=EN-US style='color:blue'>313</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from_page = to_page
= ((address&gt;&gt;20) &amp; 0xffc);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>314</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from_page +=
((p-&gt;start_code&gt;&gt;20) &amp; 0xffc);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // p</span>进程目录项。</p>

<p class=a><u><span lang=EN-US style='color:blue'>315</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; to_page += ((<u><span
style='color:blue'>current</span></u>-&gt;start_code&gt;&gt;20) &amp; 0xffc);&nbsp;
// </span>当前进程目录项。</p>

<p class=a><span lang=EN-US>&nbsp;</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>在得到<span lang=EN-US>p</span>进程和当前进程<span
lang=EN-US>address</span>对应的目录项后，下面分别对进程<span lang=EN-US>p</span>和当前进程进行处理。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>下面首先对<span lang=EN-US>p</span>进程的表项进行操作。目标是取得<span
lang=EN-US>p</span>进程中<span lang=EN-US> address</span>对应的物理内存页面地址，</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>并且该物理页面存在，而且干净（没有被修改过，不脏）。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>方法是先取目录项内容。如果该目录项无效（<span
lang=EN-US>P=0</span>），表示目录项对应的二级页表不存在，</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>于是返回。否则取该目录项对应页表地址<span
lang=EN-US>from</span>，从而计算出逻辑地址<span lang=EN-US>address</span>对应的页表项</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>指针，并取出该页表项内容临时保存在<span
lang=EN-US>phys_addr</span>中。</p>

<p class=a><u><span lang=EN-US style='color:blue'>316</span></u><span
lang=EN-US> <b><i>/* is there a page-directory at from? */</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; /* </span>在<span lang=EN-US>from</span>处是否存在页目录项？<span
lang=EN-US>*/</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>317</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from = *(unsigned
long *) from_page;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// p</span>进程目录项内容。</p>

<p class=a><u><span lang=EN-US style='color:blue'>318</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!(from &amp;
1))</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>319</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return 0;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>320</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from &amp;=
0xfffff000;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>页表地址。</p>

<p class=a><u><span lang=EN-US style='color:blue'>321</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from_page = from +
((address&gt;&gt;10) &amp; 0xffc);&nbsp;&nbsp;&nbsp; // </span>页表项指针。</p>

<p class=a><u><span lang=EN-US style='color:blue'>322</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; phys_addr =
*(unsigned long *) from_page;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // </span>页表项内容。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>接着看看页表项映射的物理页面是否存在并且干净。
<span lang=EN-US>0x41 </span>对应页表项中的<span lang=EN-US>D</span>（<span lang=EN-US>Dirty</span>）和</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // P</span>（<span lang=EN-US>Present</span>）标志。如果页面不干净或无效则返回。然后我们从该表项中取出物理页面地址</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>再保存在<span lang=EN-US>phys_addr</span>中。最后我们再检查一下这个物理页面地址的有效性，即它不应该超过</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>机器最大物理地址值，也不应该小于内存低端<span
lang=EN-US>(1MB)</span>。</p>

<p class=a><u><span lang=EN-US style='color:blue'>323</span></u><span
lang=EN-US> <b><i>/* is the page clean and present? */</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; /* </span>物理页面干净并且存在吗？<span
lang=EN-US>*/</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>324</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ((phys_addr
&amp; 0x41) != 0x01)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>325</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return 0;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>326</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; phys_addr &amp;=
0xfffff000;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>物理页面地址。</p>

<p class=a><u><span lang=EN-US style='color:blue'>327</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (phys_addr &gt;=
<u><span style='color:blue'>HIGH_MEMORY</span></u> || phys_addr &lt; <u><span
style='color:blue'>LOW_MEM</span></u>)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>328</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return 0;</span></p>

<p class=a><span lang=EN-US>&nbsp;</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>下面首先对当前进程的表项进行操作。目标是取得当前进程中<span
lang=EN-US>address</span>对应的页表项地址，</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>并且该页表项还没有映射物理页面，即其<span
lang=EN-US>P=0</span>。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>首先取当前进程页目录项内容<span
lang=EN-US style='font-family:Wingdings'>è</span><span lang=EN-US>to</span>。如果该目录项无效（<span
lang=EN-US>P=0</span>），即目录项对应的二级页表</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>不存在，则申请一空闲页面来存放页表，并更新目录项<span
lang=EN-US>to_page</span>内容，让其指向该内存页面。</p>

<p class=a><u><span lang=EN-US style='color:blue'>329</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; to = *(unsigned
long *) to_page;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>当前进程目录项内容。</p>

<p class=a><u><span lang=EN-US style='color:blue'>330</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!(to &amp; 1))</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>331</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (to = <u><span style='color:blue'>get_free_page</span></u>())</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>332</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
*(unsigned long *) to_page = to | 7;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>333</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
else</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>334</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>oom</span></u>();</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>否则取目录项中的页表地址<span
lang=EN-US style='font-family:Wingdings'>è</span><span lang=EN-US>to</span>，加上页表项索引值<span
lang=EN-US>&lt;&lt;2</span>，即页表项在表中偏移地址，得到</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>页表项地址<span lang=EN-US
style='font-family:Wingdings'>è</span><span lang=EN-US>to_page</span>。针对该页表项，如果此时我们检查出其对应的物理页面已经存在，</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>即页表项的存在位<span
lang=EN-US>P=1</span>，则说明原本我们想共享进程<span lang=EN-US>p</span>中对应的物理页面，但现在我们自己</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>已经占有了（映射有）物理页面。于是说明内核出错，死机。</p>

<p class=a><u><span lang=EN-US style='color:blue'>335</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; to &amp;=
0xfffff000;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>页表地址。</p>

<p class=a><u><span lang=EN-US style='color:blue'>336</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; to_page = to +
((address&gt;&gt;10) &amp; 0xffc);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //
</span>页表项地址。</p>

<p class=a><u><span lang=EN-US style='color:blue'>337</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (1 &amp;
*(unsigned long *) to_page)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>338</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>panic</span></u>(<i>&quot;try_to_share: to_page
already exists&quot;</i>);</span></p>

<p class=a><span lang=EN-US>&nbsp;</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>在找到了进程<span
lang=EN-US>p</span>中逻辑地址<span lang=EN-US>address</span>处对应的干净并且存在的物理页面，而且也确定了当前</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>进程中逻辑地址<span
lang=EN-US> address </span>所对应的二级页表项地址之后，我们现在对他们进行共享处理。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>方法很简单，就是首先对<span
lang=EN-US>p</span>进程的页表项进行修改，设置其写保护（<span lang=EN-US>R/W=0</span>，只读）标志，</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>然后让当前进程复制<span
lang=EN-US> p</span>进程的这个页表项。此时当前进程逻辑地址<span lang=EN-US> address </span>处页面即被</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp; &nbsp;// </span>映射到<span lang=EN-US>p</span>进程逻辑地址<span
lang=EN-US>address</span>处页面映射的物理页面上。</p>

<p class=a><u><span lang=EN-US style='color:blue'>339</span></u><span
lang=EN-US> <b><i>/* share them: write-protect */</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; /* </span>对它们进行共享处理：写保护<span
lang=EN-US> */</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>340</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *(unsigned long *)
from_page &amp;= ~2;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>341</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *(unsigned long *)
to_page = *(unsigned long *) from_page;</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>随后刷新页变换高速缓冲。计算所操作物理页面的页面号，并将对应页面映射字节数组项中</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>的引用递增<span lang=EN-US>1</span>。最后返回<span
lang=EN-US>1</span>，表示共享处理成功。</p>

<p class=a><u><span lang=EN-US style='color:blue'>342</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>invalidate</span></u>();</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>343</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; phys_addr -= <u><span
style='color:blue'>LOW_MEM</span></u>;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>344</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; phys_addr &gt;&gt;=
12;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>得页面号。</p>

<p class=a><u><span lang=EN-US style='color:blue'>345</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>mem_map</span></u>[phys_addr]++;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>346</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 1;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>347</span></u><span
lang=EN-US> }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>348</span></u><span
lang=EN-US> </span></p>

<p class=a><u><span lang=EN-US style='color:blue'>349</span></u><span
lang=EN-US> <b><i>/*</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>350</span></u><span
lang=EN-US> <b><i>&nbsp;* share_page() tries to find a process that could share
a page with</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>351</span></u><span
lang=EN-US> <b><i>&nbsp;* the current one. Address is the address of the wanted
page relative</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>352</span></u><span
lang=EN-US> <b><i>&nbsp;* to the current data space.</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>353</span></u><span
lang=EN-US> <b><i>&nbsp;*</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>354</span></u><span
lang=EN-US> <b><i>&nbsp;* We first check if it is at all feasible by checking
executable-&gt;i_count.</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>355</span></u><span
lang=EN-US> <b><i>&nbsp;* It should be &gt;1 if there are other tasks sharing
this inode.</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>356</span></u><span
lang=EN-US> <b><i>&nbsp;*/</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; /*</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * share_page()</span>试图找到一个进程，它可以与当前进程共享页面。参数<span
lang=EN-US>address</span>是</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>当前进程数据空间中期望共享的某页面地址。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; *</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>首先我们通过检测<span
lang=EN-US>executable-&gt;i_count</span>来查证是否可行。如果有其他任务已共享</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>该<span
lang=EN-US>inode</span>，则它应该大于<span lang=EN-US>1</span>。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp; &nbsp;&nbsp;*/</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; //// </span>共享页面处理。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>在发生缺页异常时，首先看看能否与运行同一个执行文件的其他进程进行页面共享处理。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>该函数首先判断系统中是否有另一个进程也在运行当前进程一样的执行文件。若有，则在</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>系统当前所有任务中寻找这样的任务。若找到了这样的任务就尝试与其共享指定地址处的</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>页面。若系统中没有其他任务正在运行与当前进程相同的执行文件，那么共享页面操作的</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>前提条件不存在，因此函数立刻退出。判断系统中是否有另一个进程也在执行同一个执行</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>文件的方法是利用进程任务数据结构中的 <span
lang=EN-US>executable </span>字段（或<span lang=EN-US>library</span>字段）。该字段</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>指向进程正在执行程序（或使用的库文件）在内存中的
<span lang=EN-US>i</span>节点。根据该 <span lang=EN-US>i</span>节点的引用次数</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // i_count </span>我们可以进行这种判断。 若节点的<span
lang=EN-US>i_count</span>值大于<span lang=EN-US>1</span>，则表明系统中有两个进程</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>正在运行同一个执行文件（或库文件），于是可以再对任务结构数组中所有任务比较是否</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>有相同的 <span lang=EN-US>executable</span>字段（或
<span lang=EN-US>library</span>字段）来最后确定多个进程运行着相同执行文件</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>的情况。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>参数<span lang=EN-US>inode</span>是欲进行共享页面进程执行文件的内存<span
lang=EN-US>i</span>节点。<span lang=EN-US>address</span>是进程中的逻辑地址，</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>即是当前进程欲与<span
lang=EN-US>p</span>进程共享页面的逻辑页面地址。返回<span lang=EN-US>1 –</span>共享操作成功，<span
lang=EN-US>0 - </span>失败。</p>

<p class=a><u><span lang=EN-US style='color:blue'>357</span></u><span
lang=EN-US> static int <u><span style='color:blue'>share_page</span></u>(struct
<u><span style='color:blue'>m_inode</span></u> * inode, unsigned long address)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>358</span></u><span
lang=EN-US> {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>359</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct <u><span
style='color:blue'>task_struct</span></u> ** p;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>360</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>首先检查一下参数指定的内存 <span
lang=EN-US>i</span>节点引用计数值。如果该内存 <span lang=EN-US>i</span>节点的引用计数值等于</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // 1</span>（<span lang=EN-US>executable-&gt;i_count
=1</span>）或者<span lang=EN-US>i</span>节点指针空，表示当前系统中只有<span lang=EN-US>1</span>个进程在运行</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>该执行文件或者提供的<span
lang=EN-US>i</span>节点无效。因此无共享可言，直接退出函数。</p>

<p class=a><u><span lang=EN-US style='color:blue'>361</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if
(inode-&gt;i_count &lt; 2 || !inode)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>362</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return 0;</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>否则搜索任务数组中所有任务。寻找与当前进程可共享页面的进程，即运行相同执行文件</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>的另一个进程，并尝试对指定地址的页面进行共享。若进程逻辑地址<span
lang=EN-US>address</span>小于进程库</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>文件在逻辑地址空间的起始地址<span
lang=EN-US>LIBRARY_OFFSET</span>，则表明共享的页面在进程执行文件对应</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>的逻辑地址空间范围内，于是检查一下指定<span
lang=EN-US>i</span>节点是否与进程的执行文件<span lang=EN-US>i</span>节点（即进程</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>的<span lang=EN-US>executable</span>相同，若不相同则继续寻找。若进程逻辑地址<span
lang=EN-US>address</span>大于等于进程库文件</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>在逻辑地址空间的起始地址<span
lang=EN-US>LIBRARY_OFFSET</span>，则表明想要共享的页面在进程使用的库文件</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>中，于是检查指定节点<span
lang=EN-US> inode </span>是否与进程的库文件<span lang=EN-US> i</span>节点相同，若不相同则继续寻找。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>如果找到某个进程<span
lang=EN-US>p</span>，其<span lang=EN-US>executable</span>或<span lang=EN-US>library</span>与指定的节点<span
lang=EN-US>inode</span>相同，则调用页面</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>试探函数<span lang=EN-US>try_to_share()
</span>尝试页面共享。若共享操作成功，则函数返回<span lang=EN-US>1</span>。否则返回<span lang=EN-US>0</span>，</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>表示共享页面操作失败。</p>

<p class=a><u><span lang=EN-US style='color:blue'>363</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (p = &amp;<u><span
style='color:blue'>LAST_TASK</span></u> ; p &gt; &amp;<u><span
style='color:blue'>FIRST_TASK</span></u> ; --p) {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>364</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (!*p)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>如果该任务项空闲，则继续寻找。</p>

<p class=a><u><span lang=EN-US style='color:blue'>365</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
continue;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>366</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (<u><span style='color:blue'>current</span></u> == *p)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>如果就是当前任务，也继续寻找。</p>

<p class=a><u><span lang=EN-US style='color:blue'>367</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
continue;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>368</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (address &lt; <u><span style='color:blue'>LIBRARY_OFFSET</span></u>) {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>369</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (inode != (*p)-&gt;executable)&nbsp;&nbsp; // </span>进程执行文件<span lang=EN-US>i</span>节点。</p>

<p class=a><u><span lang=EN-US style='color:blue'>370</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
continue;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>371</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
} else {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>372</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (inode != (*p)-&gt;library)&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;// </span>进程使用库文件<span
lang=EN-US>i</span>节点。</p>

<p class=a><u><span lang=EN-US style='color:blue'>373</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
continue;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>374</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>375</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (<u><span style='color:blue'>try_to_share</span></u>(address,*p))&nbsp;&nbsp;&nbsp;
// </span>尝试共享页面。</p>

<p class=a><u><span lang=EN-US style='color:blue'>376</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return 1;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>377</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>378</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>379</span></u><span
lang=EN-US> }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>380</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; //// </span>执行缺页处理。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp; &nbsp;// </span>访问不存在页面的处理函数，页异常中断处理过程中调用此函数。在<span
lang=EN-US>page.s</span>程序中被调用。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>函数参数<span lang=EN-US>error_code
</span>和 <span lang=EN-US>address </span>是进程在访问页面时由<span lang=EN-US> CPU</span>因缺页产生异常而自动生成。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // error_code</span>指出出错类型，参见本章开始处的“内存页面出错异常”一节；<span
lang=EN-US>address</span>是产生</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>异常的页面线性地址。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>该函数首先查看所缺页是否在交换设备中，若是则交换进来。否则尝试与已加载的相同文件</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>进行页面共享，或者只是由于进程动态申请内存页面而只需映射一页物理内存页即可。若共</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>享操作不成功，那么只能从相应文件中读入所缺的数据页面到指定线性地址处。</p>

<p class=a><u><span lang=EN-US style='color:blue'>381</span></u><span
lang=EN-US> void <u><span style='color:blue'>do_no_page</span></u>(unsigned
long error_code,unsigned long address)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>382</span></u><span
lang=EN-US> {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>383</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int nr[4];</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>384</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long tmp;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>385</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long page;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>386</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int block,i;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>387</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct <u><span
style='color:blue'>m_inode</span></u> * inode;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>388</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>首先判断<span lang=EN-US>CPU</span>控制寄存器<span
lang=EN-US>CR2</span>给出的引起页面异常的线性地址在什么范围中。如果<span lang=EN-US>address</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>小于<span lang=EN-US>
TASK_SIZE</span>（<span lang=EN-US>0x4000000</span>，即<span lang=EN-US>64MB</span>），表示异常页面位置在内核或任务<span
lang=EN-US>0</span>和任务<span lang=EN-US>1</span>所处</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>的线性地址范围内，于是发出警告信息“内核范围内存被写保护”；如果<span
lang=EN-US> (address–</span>当前</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>进程代码起始地址<span
lang=EN-US>)</span>大于一个进程的长度（<span lang=EN-US>64MB</span>），表示<span lang=EN-US>address</span>所指的线性地址不在引起</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>异常的进程线性地址空间范围内，则在发出出错信息后退出。</p>

<p class=a><u><span lang=EN-US style='color:blue'>389</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (address &lt; <u><span
style='color:blue'>TASK_SIZE</span></u>)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>390</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>printk</span></u>(<i>&quot;\n\rBAD!! KERNEL PAGE
MISSING\n\r&quot;</i>);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>391</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (address - <u><span
style='color:blue'>current</span></u>-&gt;start_code &gt; <u><span
style='color:blue'>TASK_SIZE</span></u>) {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>392</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>printk</span></u>(<i>&quot;Bad things happen:
nonexistent page error in do_no_page\n\r&quot;</i>);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>393</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>do_exit</span></u>(<u><span style='color:blue'>SIGSEGV</span></u>);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>394</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>然后根据指定的线性地址<span
lang=EN-US>address</span>求出其对应的二级页表项指针，并根据该页表项内容判断</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // address</span>处的页面是否在交换设备中。若是则调入页面并退出。方法是首先取指定线性地址</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // address</span>对应的目录项内容。如果对应的二级页表存在，则取出该目录项中二级页表的地址，</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>加上页表项偏移值即得到线性地址<span
lang=EN-US>address</span>处页面对应的页面表项指针，从而获得页表项内</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>容。若页表项内容不为<span
lang=EN-US>0</span>并且页表项存在位<span lang=EN-US>P=0</span>，则说明该页表项指定的物理页面应该在交</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>换设备中。于是从交换设备中调入指定页面后退出函数。</p>

<p class=a><u><span lang=EN-US style='color:blue'>395</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; page = *(unsigned
long *) ((address &gt;&gt; 20) &amp; 0xffc); // </span>取目录项内容。</p>

<p class=a><u><span lang=EN-US style='color:blue'>396</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (page &amp; 1) {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>397</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
page &amp;= 0xfffff000;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>二级页表地址。</p>

<p class=a><u><span lang=EN-US style='color:blue'>398</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
page += (address &gt;&gt; 10) &amp; 0xffc;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>页表项指针。</p>

<p class=a><u><span lang=EN-US style='color:blue'>399</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
tmp = *(unsigned long *) page;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>页表项内容。</p>

<p class=a><u><span lang=EN-US style='color:blue'>400</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (tmp &amp;&amp; !(1 &amp; tmp)) {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>401</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>swap_in</span></u>((unsigned long *) page);&nbsp;&nbsp;&nbsp;&nbsp;
// </span>从交换设备读页面。</p>

<p class=a><u><span lang=EN-US style='color:blue'>402</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>403</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>404</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>否则取线性空间中指定地址<span
lang=EN-US>address</span>处页面地址，并算出指定线性地址在进程空间中相对于</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>进程基址的偏移长度值<span
lang=EN-US>tmp</span>，即对应的逻辑地址。从而可以算出缺页页面在执行文件映像中</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>或在库文件中的具体起始数据块号。</p>

<p class=a><u><span lang=EN-US style='color:blue'>405</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; address &amp;=
0xfffff000;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// address</span>处缺页页面地址。</p>

<p class=a><u><span lang=EN-US style='color:blue'>406</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tmp = address - <u><span
style='color:blue'>current</span></u>-&gt;start_code;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>缺页页面对应逻辑地址。</p>

<p class=a><span lang=EN-US>&nbsp;</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>如果缺页对应的逻辑地址<span
lang=EN-US>tmp</span>大于库映像文件在进程逻辑空间中的起始位置，说明缺少的页</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>面在库映像文件中。于是从当前进程任务数据结构中可以取得库映像文件的<span
lang=EN-US>i</span>节点<span lang=EN-US>library</span>，</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>并计算出该缺页在库文件中的起始数据块号<span
lang=EN-US>block</span>。如果缺页对应的逻辑地址<span lang=EN-US>tmp</span>小于进程</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>的执行映像文件在逻辑地址空间的末端位置，则说明缺少的页面在进程执行文件映像中，于</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>是可以从当前进程任务数据机构中取得执行文件的<span
lang=EN-US>i</span>节点号<span lang=EN-US>executable</span>，并计算出该缺页</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>在执行文件映像中的起始数据块号<span
lang=EN-US>block</span>。若逻辑地址<span lang=EN-US>tmp</span>既不在执行文件映像的地址范围</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>内，也不在库文件空间范围内，则说明缺页是进程访问动态申请的内存页面数据所致，因此</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>没有对应<span lang=EN-US>i</span>节点和数据块号（都置空）。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>因为块设备上存放的执行文件映像第<span
lang=EN-US>1</span>块数据是程序头结构，因此在读取该文件时需要跳过</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>第<span lang=EN-US>1</span>块数据。所以需要首先计算缺页所在的数据块号。因为每块数据长度为<span
lang=EN-US>BLOCK_SIZE =</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // 1KB</span>，因此一页内存可存放<span
lang=EN-US>4</span>个数据块。进程逻辑地址<span lang=EN-US>tmp</span>除以数据块大小再加<span
lang=EN-US>1</span>即可得出</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>缺少的页面在执行映像文件中的起始块号<span
lang=EN-US>block</span>。</p>

<p class=a><u><span lang=EN-US style='color:blue'>407</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (tmp &gt;= <u><span
style='color:blue'>LIBRARY_OFFSET</span></u> ) {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>408</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
inode = <u><span style='color:blue'>current</span></u>-&gt;library;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>库文件<span lang=EN-US>i</span>节点和缺页起始块号。</p>

<p class=a><u><span lang=EN-US style='color:blue'>409</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
block = 1 + (tmp-<u><span style='color:blue'>LIBRARY_OFFSET</span></u>) / <u><span
style='color:blue'>BLOCK_SIZE</span></u>;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>410</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else if (tmp &lt;
<u><span style='color:blue'>current</span></u>-&gt;end_data) {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>411</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
inode = <u><span style='color:blue'>current</span></u>-&gt;executable;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;// </span>执行文件<span lang=EN-US>i</span>节点和缺页起始块号。</p>

<p class=a><u><span lang=EN-US style='color:blue'>412</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
block = 1 + tmp / <u><span style='color:blue'>BLOCK_SIZE</span></u>;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>413</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>414</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
inode = <u><span style='color:blue'>NULL</span></u>;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>是动态申请的数据或栈内存页面。</p>

<p class=a><u><span lang=EN-US style='color:blue'>415</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
block = 0;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>416</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>若是进程访问其动态申请的页面或为了存放栈信息而引起的缺页异常，则直接申请一页物</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>理内存页面并映射到线性地址<span
lang=EN-US>address</span>处即可。否则说明所缺页面在进程执行文件或库文</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>件范围内，于是就尝试共享页面操作，若成功则退出。若不成功就只能申请一页物理内存</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>页面<span lang=EN-US>page</span>，然后从设备上读取执行文件中的相应页面并放置（映射）到进程页面逻辑地址</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // tmp</span>处。</p>

<p class=a><u><span lang=EN-US style='color:blue'>417</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!inode) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>是动态申请的数据内存页面。</p>

<p class=a><u><span lang=EN-US style='color:blue'>418</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>get_empty_page</span></u>(address);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>419</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>420</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>421</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (<u><span
style='color:blue'>share_page</span></u>(inode,tmp))&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>尝试逻辑地址<span lang=EN-US>tmp</span>处页面的共享。</p>

<p class=a><u><span lang=EN-US style='color:blue'>422</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>423</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!(page = <u><span
style='color:blue'>get_free_page</span></u>()))&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>申请一页物理内存。</p>

<p class=a><u><span lang=EN-US style='color:blue'>424</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>oom</span></u>();</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>425</span></u><span
lang=EN-US> <b><i>/* remember that 1 block is used for header */</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; /* </span>记住，（程序）头要使用<span
lang=EN-US>1</span>个数据块<span lang=EN-US> */</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>根据这个块号和执行文件的<span
lang=EN-US>i</span>节点，我们就可以从映射位图中找到对应块设备中对应的设备</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>逻辑块号（保存在<span
lang=EN-US>nr[]</span>数组中）。利用<span lang=EN-US>bread_page()</span>即可把这<span
lang=EN-US>4</span>个逻辑块读入到物理页面</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // page</span>中。</p>

<p class=a><u><span lang=EN-US style='color:blue'>426</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (i=0 ; i&lt;4 ;
block++,i++)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>427</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
nr[i] = <u><span style='color:blue'>bmap</span></u>(inode,block);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>428</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>bread_page</span></u>(page,inode-&gt;i_dev,nr);</span></p>

<p class=a><span lang=EN-US>&nbsp;</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>在读设备逻辑块操作时，可能会出现这样一种情况，即在执行文件中的读取页面位置可能离</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>文件尾不到<span lang=EN-US>1</span>个页面的长度。因此就可能读入一些无用的信息。下面的操作就是把这部分超</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>出执行文件<span lang=EN-US>end_data</span>以后的部分进行清零处理。当然，若该页面离末端超过<span
lang=EN-US>1</span>页，说明不</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>是从执行文件映像中读取的页面，而是从库文件中读取的，因此不用执行清零操作。</p>

<p class=a><u><span lang=EN-US style='color:blue'>429</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i = tmp + 4096 - <u><span
style='color:blue'>current</span></u>-&gt;end_data;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>超出的字节长度值。</p>

<p class=a><u><span lang=EN-US style='color:blue'>430</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (i&gt;4095)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>离末端超过<span lang=EN-US>1</span>页则不用清零。</p>

<p class=a><u><span lang=EN-US style='color:blue'>431</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
i = 0;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>432</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tmp = page + 4096;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//
tmp</span>指向页面末端。</p>

<p class=a><u><span lang=EN-US style='color:blue'>433</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (i-- &gt; 0)
{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>页面末端<span lang=EN-US>i</span>字节清零。</p>

<p class=a><u><span lang=EN-US style='color:blue'>434</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
tmp--;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>435</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
*(char *)tmp = 0;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>436</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>最后把引起缺页异常的一页物理页面映射到指定线性地址<span
lang=EN-US>address</span>处。若操作成功就返回。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>否则就释放内存页，显示内存不够。</p>

<p class=a><u><span lang=EN-US style='color:blue'>437</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (<u><span
style='color:blue'>put_page</span></u>(page,address))</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>438</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>439</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>free_page</span></u>(page);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>440</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>oom</span></u>();</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>441</span></u><span
lang=EN-US> }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>442</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; //// </span>物理内存管理初始化。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>该函数对<span lang=EN-US>1MB</span>以上内存区域以页面为单位进行管理前的初始化设置工作。一个页面长度为</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // 4KB</span>字节。该函数把<span
lang=EN-US> 1MB</span>以上所有物理内存划分成一个个页面，并使用一个页面映射字节</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>数组<span lang=EN-US>mem_map[]
</span>来管理所有这些页面。对于具有<span lang=EN-US>16MB</span>内存容量的机器，该数组共有<span lang=EN-US>3840</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>项<span lang=EN-US>
((16MB - 1MB)/4KB)</span>，即可管理<span lang=EN-US>3840</span>个物理页面。每当一个物理内存页面被占用时就</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>把<span lang=EN-US>
mem_map[]</span>中对应的的字节值增<span lang=EN-US>1</span>；若释放一个物理页面，就把对应字节值减<span
lang=EN-US>1</span>。 若字</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>节值为<span lang=EN-US> 0</span>，则表示对应页面空闲；
若字节值大于或等于<span lang=EN-US>1</span>，则表示对应页面被占用或被不</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>同程序共享占用。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>在该版本的 <span
lang=EN-US>Linux</span>内核中，最多能管理<span lang=EN-US> 16MB</span>的物理内存，大于<span
lang=EN-US>16MB</span>的内存将弃置不用。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>对于具有<span lang=EN-US>16MB</span>内存的<span
lang=EN-US>PC</span>机系统，在没有设置虚拟盘 <span lang=EN-US>RAMDISK</span>的情况下 <span
lang=EN-US>start_mem</span>通常</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>是<span lang=EN-US>4MB</span>，<span
lang=EN-US>end_mem</span>是<span lang=EN-US>16MB</span>。因此此时主内存区范围是<span
lang=EN-US>4MB—16MB</span>，共有<span lang=EN-US>3072</span>个物理页面可</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>供分配。而范围<span
lang=EN-US>0 - 1MB</span>内存空间用于内核系统（其实内核只使用<span lang=EN-US>0 —640Kb</span>，剩下的部</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>分被部分高速缓冲和设备内存占用）。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>参数<span lang=EN-US>start_mem</span>是可用作页面分配的主内存区起始地址（已去除<span
lang=EN-US>RAMDISK</span>所占内存空间）。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // end_mem</span>是实际物理内存最大地址。而地址范围<span
lang=EN-US>start_mem</span>到<span lang=EN-US>end_mem</span>是主内存区。</p>

<p class=a><u><span lang=EN-US style='color:blue'>443</span></u><span
lang=EN-US> void <u><span style='color:blue'>mem_init</span></u>(long
start_mem, long end_mem)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>444</span></u><span
lang=EN-US> {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>445</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>446</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>首先将<span lang=EN-US>1MB</span>到<span
lang=EN-US>16MB</span>范围内所有内存页面对应的内存映射字节数组项置为已占用状态，即各</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>项字节值全部设置成<span
lang=EN-US>USED</span>（<span lang=EN-US>100</span>）。<span lang=EN-US>PAGING_PAGES</span>被定义为<span
lang=EN-US>(PAGING_MEMORY&gt;&gt;12)</span>，即<span lang=EN-US>1MB</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>以上所有物理内存分页后的内存页面数<span
lang=EN-US>(15MB/4KB = 3840)</span>。</p>

<p class=a><u><span lang=EN-US style='color:blue'>447</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>HIGH_MEMORY</span></u> = end_mem;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>设置内存最高端（<span lang=EN-US>16MB</span>）。</p>

<p class=a><u><span lang=EN-US style='color:blue'>448</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (i=0 ; i&lt;<u><span
style='color:blue'>PAGING_PAGES</span></u> ; i++)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>449</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>mem_map</span></u>[i] = <u><span style='color:blue'>USED</span></u>;</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>然后计算主内存区起始内存<span
lang=EN-US> start_mem </span>处页面对应内存映射字节数组中项号<span lang=EN-US>i</span>和主内存区</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>页面数。此时 <span
lang=EN-US>mem_map[] </span>数组的第<span lang=EN-US>i</span>项正对应主内存区中第<span
lang=EN-US>1</span>个页面。最后将主内存区中</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>页面对应的数组项清零（表示空闲）。对于具有<span
lang=EN-US>16MB</span>物理内存的系统，<span lang=EN-US>mem_map[] </span>中对应</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // 4Mb--16Mb</span>主内存区的项被清零。</p>

<p class=a><u><span lang=EN-US style='color:blue'>450</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i = <u><span
style='color:blue'>MAP_NR</span></u>(start_mem);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// </span>主内存区起始位置处页面号。</p>

<p class=a><u><span lang=EN-US style='color:blue'>451</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end_mem -=
start_mem;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>452</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end_mem &gt;&gt;=
12;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>主内存区中的总页面数。</p>

<p class=a><u><span lang=EN-US style='color:blue'>453</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while
(end_mem--&gt;0)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>454</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>mem_map</span></u>[i++]=0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>主内存区页面对应字节值清零。</p>

<p class=a><u><span lang=EN-US style='color:blue'>455</span></u><span
lang=EN-US> }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>456</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>显示系统内存信息。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>根据内存映射字节数组<span
lang=EN-US> mem_map[] </span>中的信息以及页目录和页表内容统计系统中使用的内存页</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>面数和主内存区中总物理内存页面数。该函数在<span
lang=EN-US> chr_drv/keyboard.S</span>程序第<span lang=EN-US>186</span>行被调用。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>即当按下“<span lang=EN-US>Shift
+ Scroll Lock</span>”组合键时会显示系统内存统计信息。</p>

<p class=a><u><span lang=EN-US style='color:blue'>457</span></u><span
lang=EN-US> void <u><span style='color:blue'>show_mem</span></u>(void)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>458</span></u><span
lang=EN-US> {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>459</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i,j,k,<u><span
style='color:blue'>free</span></u>=0,total=0;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>460</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int shared=0;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>461</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long *
pg_tbl;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>462</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>根据内存映射字节数组<span
lang=EN-US>mem_map[]</span>，统计系统主内存区页面总数<span lang=EN-US>total</span>，以及其中空闲页面</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>数<span lang=EN-US>free</span>和被共享的页面数<span
lang=EN-US>shared</span>。并这些信息显示。</p>

<p class=a><u><span lang=EN-US style='color:blue'>463</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>printk</span></u>(<i>&quot;Mem-info:\n\r&quot;</i>);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>464</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(i=0 ; i&lt;<u><span
style='color:blue'>PAGING_PAGES</span></u> ; i++) {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>465</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (<u><span style='color:blue'>mem_map</span></u>[i] == <u><span
style='color:blue'>USED</span></u>)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// 1MB</span>以上内存系统占用的页面。</p>

<p class=a><u><span lang=EN-US style='color:blue'>466</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
continue;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>467</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
total++;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>468</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (!<u><span style='color:blue'>mem_map</span></u>[i])</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>469</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>free</span></u>++;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>主内存区空闲页面统计。</p>

<p class=a><u><span lang=EN-US style='color:blue'>470</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
else</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>471</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
shared += <u><span style='color:blue'>mem_map</span></u>[i]-1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>共享的页面数（字节值<span lang=EN-US>&gt;1</span>）。</p>

<p class=a><u><span lang=EN-US style='color:blue'>472</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>473</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>printk</span></u>(<i>&quot;%d free pages of %d\n\r&quot;</i>,<u><span
style='color:blue'>free</span></u>,total);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>474</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>printk</span></u>(<i>&quot;%d pages shared\n\r&quot;</i>,shared);</span></p>

<p class=a><span lang=EN-US>&nbsp;</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>统计处理器分页管理逻辑页面数。页目录表前<span
lang=EN-US>4</span>项供内核代码使用，不列为统计范围，因此</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>扫描处理的页目录项从第<span
lang=EN-US>5</span>项开始。方法是循环处理所有页目录项（除前<span lang=EN-US>4</span>个项），若对应</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>的二级页表存在，那么先统计二级页表本身占用的内存页面（<span
lang=EN-US>484</span>行），然后对该页表中所</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>有页表项对应页面情况进行统计。</p>

<p class=a><u><span lang=EN-US style='color:blue'>475</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; k = 0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>一个进程占用页面统计值。</p>

<p class=a><u><span lang=EN-US style='color:blue'>476</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(i=4 ; i&lt;1024
;) {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>477</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (1&amp;<u><span style='color:blue'>pg_dir</span></u>[i]) {</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>（如果页目录项对应二级页表地址大于机器最高物理内存地址<span
lang=EN-US>HIGH_MEMORY</span>，则说明该目录项</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>有问题。于是显示该目录项信息并继续处理下一个目录项。）</p>

<p class=a><u><span lang=EN-US style='color:blue'>478</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (<u><span style='color:blue'>pg_dir</span></u>[i]&gt;<u><span
style='color:blue'>HIGH_MEMORY</span></u>) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>目录项内容不正常。</p>

<p class=a><u><span lang=EN-US style='color:blue'>479</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>printk</span></u>(<i>&quot;page directory[%d]:
%08X\n\r&quot;</i>,</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>480</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i,<u><span
style='color:blue'>pg_dir</span></u>[i]);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>481</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
continue;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// continue</span>之前需插入<span lang=EN-US>i++</span>；</p>

<p class=a><u><span lang=EN-US style='color:blue'>482</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>如果页目录项对应二级页表的“地址”大于<span
lang=EN-US>LOW_MEM</span>（即<span lang=EN-US>1MB</span>），则把一个进程占用的物理</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>内存页统计值<span
lang=EN-US>k</span>增<span lang=EN-US>1</span>，把系统占用的所有物理内存页统计值<span lang=EN-US>free</span>增<span
lang=EN-US>1</span>。然后取对应页表地址</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // pg_tbl</span>，并对该页表中所有页表项进行统计。如果当前页表项所指物理页面存在并且该物理</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>页面“地址”大于<span
lang=EN-US>LOW_MEM</span>，那么就将页表项对应页面纳入统计值。</p>

<p class=a><u><span lang=EN-US style='color:blue'>483</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (<u><span style='color:blue'>pg_dir</span></u>[i]&gt;<u><span
style='color:blue'>LOW_MEM</span></u>)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>484</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>free</span></u>++,k++;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>统计页表占用页面。</p>

<p class=a><u><span lang=EN-US style='color:blue'>485</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
pg_tbl=(unsigned long *) (0xfffff000 &amp; <u><span style='color:blue'>pg_dir</span></u>[i]);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>486</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
for(j=0 ; j&lt;1024 ; j++)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>487</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if ((pg_tbl[j]&amp;1) &amp;&amp; pg_tbl[j]&gt;<u><span style='color:blue'>LOW_MEM</span></u>)</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>（若该物理页面地址大于机器最高物理内存地址<span
lang=EN-US>HIGH_MEMORY</span>，则说明该页表项内容有问题，</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>于是显示该页表项内容。否则将页表项对应页面纳入统计值。）</p>

<p class=a><u><span lang=EN-US style='color:blue'>488</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (pg_tbl[j]&gt;<u><span style='color:blue'>HIGH_MEMORY</span></u>)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>489</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>printk</span></u>(<i>&quot;page_dir[%d][%d]:
%08X\n\r&quot;</i>,</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>490</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
i,j, pg_tbl[j]);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>491</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>492</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
k++,<u><span style='color:blue'>free</span></u>++;&nbsp; // </span>统计页表项对应页面。</p>

<p class=a><u><span lang=EN-US style='color:blue'>493</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>因每个任务线性空间长度是<span
lang=EN-US>64MB</span>，所以一个任务占用<span lang=EN-US>16</span>个目录项。因此这里每统计了<span
lang=EN-US>16</span>个</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>目录项就把进程的任务结构占用的页表统计进来。若此时<span
lang=EN-US>k=0</span>则表示当前的<span lang=EN-US>16</span>个页目录所对</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>应的进程在系统中不存在（没有创建或者已经终止）。
在显示了对应进程号和其占用的物理</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>内存页统计值<span
lang=EN-US>k</span>后，将<span lang=EN-US>k</span>清零，以用于统计下一个进程占用的内存页面数。</p>

<p class=a><u><span lang=EN-US style='color:blue'>494</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
i++;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>495</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (!(i&amp;15) &amp;&amp; k) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// k !=0 </span>表示相应进程存在。</p>

<p class=a><u><span lang=EN-US style='color:blue'>496</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
k++,<u><span style='color:blue'>free</span></u>++;&nbsp;&nbsp;&nbsp;&nbsp; <b><i>/*
one page/process for task_struct */</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>497</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>printk</span></u>(<i>&quot;Process %d: %d
pages\n\r&quot;</i>,(i&gt;&gt;4)-1,k);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>498</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
k = 0;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>499</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>500</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>最后显示系统中正在使用的内存页面和主内存区中总的内存页面数。</p>

<p class=a><u><span lang=EN-US style='color:blue'>501</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>printk</span></u>(<i>&quot;Memory found: %d (%d)\n\r&quot;</i>,<u><span
style='color:blue'>free</span></u>-shared,total);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>502</span></u><span
lang=EN-US> }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>503</span></u><span
lang=EN-US> </span></p>

<div class=a align=center style='text-align:center'><span lang=EN-US>

<hr size=4 width="100%" align=center>

</span></div>

<p class=MsoNormal><span lang=EN-US>&nbsp;</span></p>

</div>

</body>

</html>
